2015年9月25日金曜日

Maya色管理6 LightColor

ライトの色はレンダリング空間のRGB値を入力すること。
特に彩度が高いライト色はレンダ空間に合わせた数値にしないと見え方が変わってしまう。
これはMaya色管理3 数値入力のところで説明した通り

ライトの色変換のテスト

例えばsRGB(D65)[1, 0.5, 0.3]の色は
XYZ(D65)では[0.645,0.592,0.334]
ACEScg(D60)では[0.797  0.532  0.364]
とすれば同じ色を表せる

カラーチェッカーのテクスチャは入力カラースペースを指定している状態で、ライトは正面からの並行光源を当てた状態でテスト。

ライトのRGB値 [1, 0.5, 0.3] で統一した場合



ライトの色が同じになるようにした場合 (sRGBの[1, 0.5, 0.3]に合わせて変換)



ライトの色が一致したことがわかる。
ライティングされたパッチの色がレンダリング空間ごとに違うのは仕方のないことで、詳細はレンダリング時の色空間
レンダ空間による色ずれの影響が少ない4段目の無彩色のパッチを見ると差がほとんどないので正しく変換された数値でライティングされていることがわかる

実はRGB(1,1,1)のライトの場合は各レンダ空間へ変換しても(1,1,1)になる場合が多い

下記がライトの色変換に使用したマトリクス

sRGB to レンダ空間マトリクス(白色変更はcat02)
sRGB(D65) to XYZ(D65)
 0.4123907993  0.3575843394  0.1804807884
 0.2126390059  0.7151686788  0.0721923154
 0.0193308187  0.1191947798  0.9505321523
sRGB(D65) to ACEScg(D60)
 0.6130828922  0.3411670543  0.0457500538
 0.0700035498  0.9180628305  0.0119336198
 0.0204907778  0.1067639876  0.8727452346


ライトの現在の色を目的の色空間へ変換するPyMel

今回のテストで使用したPyMel
すべてのライトタイプのcolorアトリビュートが変更される
48行目で現在の色空間と白色点、目的の色空間と白色点を指定する

import pymel.core as pm
from numpy import *

#白色点のXnYnZnの配列 (3*1mat)
arrMatLightXYZ = [
matrix('1.0;1.0;1.0'),                       #E   from(x,y = 1/3,1/3)
matrix('1.09849061235,1,0.355798257455'),    #A   from(x,y = 0.44758,0.40745)
matrix('0.98070597166;1;1.18224949393'),     #C   from(x,y = 0.31006,0.31616)
matrix('0.96429567643;1;0.82510460251'),     #D50 from(x,y = 0.3457,0.3585)
matrix('0.95264607457;1.0;1.00882518435'),   #D60 from(x,y = 0.32168,0.33767)
matrix('0.950455927052;1.0;1.08905775076'),  #D65 from(x,y = 0.3127,0.3290)
matrix('0.894586894587;1.0;0.954415954416')] #dci from(x,y = 0.3140,0.3510)
arrKeyLightXYZ = ["E","A","C","D50","D60","D65","dci"]
arrMatLightXYZ = dict(zip(arrKeyLightXYZ,arrMatLightXYZ))

#XYZtoRGBの配列  (3*3mat)
arrMatXYZ2RGB = [
matrix('1 0 0; 0 1 0; 0 0 1'), #ZYZ(E)
matrix('3.2409699419 -1.5373831776 -0.4986107603; -0.9692436363 1.8759675015 0.0415550574;0.0556300797 -0.2039769589 1.0569715142'), #sRGB(D65)
matrix('2.7253940305 -1.0180030062 -0.4401631952; -0.7951680258 1.6897320548 0.0226471906;0.0412418914 -0.0876390192 1.1009293786'), #DCI-P3
matrix('1.716651188 -0.3556707838 -0.2533662814; -0.6666843518 1.6164812366 0.0157685458;0.0176398574 -0.0427706133 0.9421031212'), #Rec.2020
matrix('1.6410233797 -0.3248032942 -0.236424695; -0.6636628587 1.6153315917 0.0167563477; 0.0117218943 -0.0082844420 0.9883948585'), #ACESap1(D60)
matrix('1.0498110175 0 -0.0000974845; -0.4959030231 1.3733130458 0.0982400361; 0 0 0.9912520182'),                                   #ACESap0(D60)
matrix('1.2694188828 -0.0988302413 -0.1705886415; -0.8363858117 1.8007170555 0.0356687562; 0.0297300599 -0.0314712627 1.0017412028')] #SharpRGB(E)
arrKeyXYZ2RGB = ["XYZ","sRGB","P3","2020","ACESap1","ACESap0","SharpRGB"]
arrMatXYZ2RGB = dict(zip(arrKeyXYZ2RGB,arrMatXYZ2RGB))

#白色点変更メソッドはcat02
mAdaptation = matrix('0.7328 0.4296 -0.1624; -0.7036 1.6975 0.0061; 0.003 0.0136 0.9834')

#変換先の色空間へ変換するマトリクスを求める関数(変換元の色空間名,変換先の色空間名,変換元の白色点,変換先の白色点 を指定する)
def getMatrixRGBtoRGB(sourceXYZtoRGBname,destXYZtoRGBname,sourceWname,destWname):
    print '変換元:',sourceXYZtoRGBname,'  変換先:',destXYZtoRGBname,'  変換元白色点:',sourceWname,'  変換先白色点:',destWname,'\n'
    #---LMSスケールを求める---
    lmsS = mAdaptation * arrMatLightXYZ[sourceWname]
    lmsD = mAdaptation * arrMatLightXYZ[destWname]
    mScale = matrix(zeros((3, 3)))     #対角行列を入れる準備
    fill_diagonal(mScale,(lmsD/lmsS))  #対角行列を作成
    #---白色点変換マトリクス---
    mChangeW = mAdaptation.I* mScale * mAdaptation
    #---レンダ空間変換マトリクス(from XYZ)---
    mRGBtoRGB = arrMatXYZ2RGB[destXYZtoRGBname] * mChangeW * arrMatXYZ2RGB[sourceXYZtoRGBname].I
    print "sourceRGB to destRGB matrix: \n",mRGBtoRGB,'\n'
    return mRGBtoRGB

#**** 変換前色空間と変換先色空間、さらに変換前白色と変換先白色の4個の名前を指定する   ****
#**** 色空間 XYZ sRGB P3 2020 ACESap1 ACESap0 SharpRGB| 白色点 E A C D50 D60 D65 dci (白色点変更しない場合は双方同じものを入れておけば何でもよい)****
mRGBtoRGB = getMatrixRGBtoRGB('sRGB','XYZ',"D65","D65")

#ここからmaya部分。ライトカラーを取得して目的の色空間の値へ変更
oLightList = pm.ls(type = 'light') #シーン中のライトを取得
for olight in oLightList:
    sourceColor = olight.color.get() #現在の色を取得
    #sourceColor = (1,0.5,0.3) # 指定値から変換したい場合
    mSourceColor = matrix(sourceColor).T #色をマトリクス3*1マトリクスに格納
    destColor = mRGBtoRGB * mSourceColor #色変換
    destColor = (destColor[0,0],destColor[1,0],destColor[2,0]) #色をセットするために3*1マトリクスからタプルに変更
    olight.color.set(destColor) #色をセット
    print '変換したライト','{: ^30}'.format(olight),'変換前の値',around(sourceColor,5),'   変換後の値',around(destColor,5)

数値入力でもカラーマネジメントをしたい場合の例15/09/30追記

少し強引だけど出来た。もっとシンプルな方法もありそうだけど...

ライトの色やマテリアルの色を入力する時に下図のように組まれたものを使う。カラー入力と同時に入力スペースの情報も入れておく。
こうすれば元の値を保持することができ、レンダリングスペースが変わったとしても半自動で対応できる。
画像はsRGB(D65) to XYZ(D65)。 入力値はリニアRGBなのでデガンマはしていない


ハイパーシェードのノードはコンパウンドできないのかな?。あとコメントやグループのノードもほしい
この場合例えば下記スクリプトで変換マトリクスが更新される。入力スペースを参照して現在のレンダリングスペースへの変換マトリクスが作られる。

import pymel.core as pm
from numpy import *

#白色点のXnYnZnの配列 (3*1mat)
arrMatLightXYZ = [
matrix('1.0;1.0;1.0'),                       #E   from(x,y = 1/3,1/3)
matrix('1.09849061235;1;0.355798257455'),    #A   from(x,y = 0.44758,0.40745)
matrix('0.98070597166;1;1.18224949393'),     #C   from(x,y = 0.31006,0.31616)
matrix('0.96429567643;1;0.82510460251'),     #D50 from(x,y = 0.3457,0.3585)
matrix('0.95264607457;1.0;1.00882518435'),   #D60 from(x,y = 0.32168,0.33767)
matrix('0.950455927052;1.0;1.08905775076'),  #D65 from(x,y = 0.3127,0.3290)
matrix('0.894586894587;1.0;0.954415954416')] #dci from(x,y = 0.3140,0.3510)
arrKeyLightXYZ = ["e","a","c","d50","d60","d65","dci"]
arrMatLightXYZ = dict(zip(arrKeyLightXYZ,arrMatLightXYZ))

#XYZtoRGBの配列  (3*3mat)
arrMatXYZ2RGB = [
matrix('1 0 0; 0 1 0; 0 0 1'), #ZYZ(E)
matrix('3.2409699419 -1.5373831776 -0.4986107603; -0.9692436363 1.8759675015 0.0415550574;0.0556300797 -0.2039769589 1.0569715142'), #sRGB(D65)
matrix('2.7253940305 -1.0180030062 -0.4401631952; -0.7951680258 1.6897320548 0.0226471906;0.0412418914 -0.0876390192 1.1009293786'), #DCI-P3
matrix('1.716651188 -0.3556707838 -0.2533662814; -0.6666843518 1.6164812366 0.0157685458;0.0176398574 -0.0427706133 0.9421031212'), #Rec.2020
matrix('1.6410233797 -0.3248032942 -0.236424695; -0.6636628587 1.6153315917 0.0167563477; 0.0117218943 -0.0082844420 0.9883948585'), #ACESap1(D60)
matrix('1.0498110175 0 -0.0000974845; -0.4959030231 1.3733130458 0.0982400361; 0 0 0.9912520182'),                                   #ACESap0(D60)
matrix('1.2694188828 -0.0988302413 -0.1705886415; -0.8363858117 1.8007170555 0.0356687562; 0.0297300599 -0.0314712627 1.0017412028')] #SharpRGB(E)
arrKeyXYZ2RGB = ["xyz","srgb","p3","2020","ap1","ap0","sharp"]
arrMatXYZ2RGB = dict(zip(arrKeyXYZ2RGB,arrMatXYZ2RGB))

#白色点変更メソッドはcat02
mAdaptation = matrix('0.7328 0.4296 -0.1624; -0.7036 1.6975 0.0061; 0.003 0.0136 0.9834')

#変換先の色空間へ変換するマトリクスを求める関数(変換元の色空間名,変換先の色空間名,変換元の白色点,変換先の白色点 を指定する)
def getMatrixRGBtoRGB(sourceXYZtoRGBname,destXYZtoRGBname,sourceWname,destWname):
    print '変換元:',sourceXYZtoRGBname,'  変換先:',destXYZtoRGBname,'  変換元白色点:',sourceWname,'  変換先白色点:',destWname,'\n'

    #---LMSスケールを求める---
    lmsS = mAdaptation * arrMatLightXYZ[sourceWname]
    lmsD = mAdaptation * arrMatLightXYZ[destWname]
    mScale = matrix(zeros((3, 3)))     #対角行列を入れる準備
    fill_diagonal(mScale,(lmsD/lmsS))  #対角行列を作成
    #---白色点変換マトリクス---
    mChangeW = mAdaptation.I* mScale * mAdaptation
    
    #---レンダ空間変換マトリクス(from XYZ)---
    mRGBtoRGB = arrMatXYZ2RGB[destXYZtoRGBname] * mChangeW * arrMatXYZ2RGB[sourceXYZtoRGBname].I
    
    set_printoptions(suppress=True,precision=10) #少数10桁表示
    print "sourceRGB to destRGB matrix: \n",mRGBtoRGB,'\n'
    return mRGBtoRGB

#ここから下がMaya部分
rsnList = ["ACES2065-1","ACEScg","scene-linear CIE XYZ","scene-linear DCI-P3","scene-linear Rec 2020","scene-linear Rec 709/sRGB","Sharp RGB"]
rsnSortNameList = ["ap0","ap1","xyz","p3","2020","srgb","sharp"]
wihteList = ["d60","d60","d65","dci","d65","d65","e"]

#現在のレンダリング色空間の取得し変数に設定
rsn = pm.colorManagementPrefs(q=True, renderingSpaceName=True)
destRgbSpace = rsnSortNameList[rsnList.index(rsn)] #レンダリング空間の簡易名
destWhite = wihteList[rsnList.index(rsn)] #レンダリング空間に対応する白色点の名前を指定する

#専用のアトリビュートを持たせたハイパーシェードノードを起点として目的のノードに対して求めたマトリクスを入力する。(接続先のノードの入力1に接続されているノードに対して)
ComposeMlist = pm.ls(type = 'composeMatrix') #composeMatrixタイプのノードを取得
for ComposeMnode in ComposeMlist:
    if ComposeMnode.hasAttr("myColorConvert"): #myColorConvertというアトリビュートがあれば以下を実行。
        myAttrVal = ComposeMnode.myColorConvert.get() #アトリビュートの値を取得。入力スペースと白色点の取得
        if myAttrVal != None:
            sourceRgbSpace,sourceWhite = myAttrVal.split(",")
            m = getMatrixRGBtoRGB(sourceRgbSpace,destRgbSpace,sourceWhite,destWhite) #入力色空間からレンダリング色空間へ変換するマトリクスの取得
            m2 = pm.datatypes.Matrix([[m[0,0],m[0,1],m[0,2],0],[m[1,0],m[1,1],m[1,2],0],[m[2,0],m[2,1],m[2,2],0],[0,0,0,0]]) #NumPyのマトリクスからPyMelのマトリクスに変換
            if len(ComposeMnode.outputMatrix.connections()) > 0 :
                MultMatrixNode = ComposeMnode.outputMatrix.connections()[0] 
                if len(MultMatrixNode.matrixIn[0].connections()) > 0 :
                    ComposeMnode2 = MultMatrixNode.matrixIn[0].connections()[0]
                    ComposeMnode2.outputMatrix.set(m2) #値のセット

2015年9月22日火曜日

Maya色管理5 colorCheckerのテクスチャ

前回はレンダリング空間とカラー値について調べたが、今回はテクスチャ入力について調べる。
カラー値の入力では今のところ入力カラースペースが指定できず、レンダ空間または表示空間で入力することになったが、テクスチャの場合は入力カラースペースを指定できる。

例えば下図のように用途に合わせて好きな色空間を指定できる。
デフォルトはsRGBだが現実にある高彩度な色を使わない場合はこれがよい。
作業環境がadobeRGBの場合は入力カラースペースもadobeRGBがよい。
正しい色のテクスチャを用意したい場合は計測ベースの色となると思うので場合はXYZやACES2065-1が良いと思う。
また法線マップはRGBを利用しているが色ではないのでカラー管理してはダメ。
ライトの色もテクスチャで指定出来ればカラー管理させることができると思う。


入力するカラーテクスチャの色空間は理論的には何でもよい。
但し狭い色空間で広範囲の色を扱うとマイナスがでてくる。
OpenEXRではマイナスを持たせることができるため理論上どんな空間でもテクスチャを持っても良いことになるが前回カラー値の入力で不具合があったのでテクスチャでは問題ないかを確認する

自己発光のテクスチャでダイナミックレンジや諧調が必要となる場合はopenEXRが良い。
ディフューズは8ビットテクスチャでも良いと思っているがXYZ空間等の広い色域で持つと諧調劣化が目立つかもしれないのでこのあたりも後日調査したい。

テクスチャ入力のカラースペースの機能をテスト

異なるカラースペースで同じテクスチャを用意する。
もちろんテクスチャのRGB値はそれぞれ違う色だが、レンダリングに渡されるときにはすべて同じ色になるはずなのでそれを検証した

用意したテクスチャ

CIE XYZ(E) のカラーチェッカーをホワイトバランスをD65に合わせたテクスチャを下記のカラースペースで用意した
これらのテクスチャのRGBの値はそれぞれ違うが、同じ色を表していると考えるとよい

入力テクスチャの色空間と白色点 拡張子 画像
scene-linear CIE XYZ : D65 .exr
ACES2065-1 : D60 .exr
ACEScg : D60 .exr
scene-linear Rec709/sRGB : D65 .exr
sRGB : D65 exr
sRGB : D65 tiff

Noboru Ohta (1997)の分光反射率をそのままXYZ値にした色をcat02の白色変更でホワイトバランスを合わせたもの。
ホワイトバランスは入色空間の規格に合わせた。

Maya色管理4 colorCheckerの数値のところのPyMelでそれぞれのカラーチェッカーを作成してレンダリングしたものをテクスチャ化した

プレビュー結果

レンダ空間はXYZ、表示空間はsRGBとした



プレビュー結果はすべて同じ色に見えるので、それぞれのテクスチャが正しくレンダリング空間へ変換できている。
但し、no18のCyanに関しては入力がsRGB8bitの時のみ色に差が出ている。これは8bitなので負の値がクランプされてしまったために起きていると思う。

負の値のテスト

前にテクスチャではなくカラーの値を入れる時に表示空間で負の値を入れるとバグっぽい問題があったがテクスチャでは問題ないかをテストした。
前回と同様にxyY(0.1, 0.7, 0.5) の色であるXYZ(0.0714, 0.5, 0.1429)を異なる色空間のテクスチャとして用意した


入力テクスチャの色空間と白色点RGB値RGB値8bitフォーマット画像
scene-linear CIE XYZ : D65 0.0523
0.5087
0.1559
13
130
40
.exr
ACES2065-1 : D60 0.0573
0.6857
0.1428
15
175
36
.exr
ACEScg : D60 -0.1098
0.7880
0.1388
-28
201
35
.exr
scene-linear Rec709/sRGB : D65 -0.6901
0.9101
0.0640
-176
232
16
.exr
sRGB : D65 -0.8489
0.9594
0.2805
-216
245
72
exr
sRGB : D65 0
0.9594
0.2805
0
245
72
tiff



プレビュー結果

レンダ空間はXYZ、表示空間はsRGBとした
8bitテクスチャ以外はほぼ同じ値として変換され、マイナス値も正しく変換できていることが解る
8bitテクスチャではマイナスが持ていないため正しく変換できない。


カラー値入力のテストのときはマイナス入力にバグっぽい問題があったがテクスチャでは大丈夫そう

入力テクスチャとして使用できるもの

sRGB

一般的にこれが一番無難だが、色域外の色の取り扱いに注意。
sRGB色域外を表す場合はテクスチャに負の値を持たせることになり、openEXRのフォーマットが必要になる(他にも負の値が持てるフォーマットはあるかもしれないがよくわからない)

scene-linear CIE XYZ、ACES2065-1、ACEScg

広範囲の色を再現するのに向いていると思ったがリニア空間での入力となるので8bitでは諧調が足りないのでFloatのフォーマットが必要。
scene-linear CIE XYZ、ACES2065-1では負の値は出てこない。

sRGBのように暗部諧調が優先され、さらに色域が広いものが欲しい。例えばgamma2.2XYZみたいな。

マニュアルをみてみる

http://help.autodesk.com/view/MAYAUL/2016/JPN//?guid=GUID-2622A6C2-B79B-442E-B5C3-327474409CC7
原色の欄に”変換されない”と書かれているものはレンダ空間に変換されない物らしい

レンダ空間に変換されないものないもの
  • Raw
  • 対数→リニア(Cineon)
  • 対数 → リニア(jzp)
レンダ空間の値を直で持つテクスチャとして扱うことなので注意が必要だが、
レンダ空間を後から変更することがなければ[対数→リニア]等は積極的に使っても良いかもしれない。ただ[対数→リニア]がどんなものかまだよくわかっていない
log系のカーブを持ち、レンダ空間に変換されるもの。
  • ARRI LogC
  • ログ フィルム スキャン(ADX)
  • Sony SLog2
この辺はよくわからないが色域は広そう。 色域も広くlog系なのでテクスチャに向いているかも。
Sony SLog2の色域はS-GAMUT?。

色域の広いXYZやACESの入力テクスチャでガンマ空間を受け付けないのが問題かも。(その場合はカスタム入力変換が必要そう)。
結局何を使えばよいかは解らないが、狭い色域で十分表せるものはsRGB。広い色域を8bitテクスチャで持たせる場合log系のものがよさそう。
openEXRで持って良いなら選択肢は増える。
XYZは見た目が解りずらいのでテクスチャ編集には向いていないかも。


次は色空間とライトの検証をする
2015年9月15日火曜日

Maya色管理4 colorCheckerの数値


前回の調査でカラー値はレンダリング空間に合わせた数値入力が必要ということがわかたった。
今回はカラーチェッカーの値が正しく表示されるように各レンダ空間に適した色を入力してみる。

重要 : テクスチャの場合は入力空間の指定ができるので各レンダ空間毎にテクスチャを用意する必要は基本的にはない

Color Cheker の素材

本当は各レンダリング空間に合わせた白色光を当てたカラーチェーカーを用意したほうが良いが、白色点変更を施した値を使うのでも誤差は少ない。

今回はカラーチェッカーの分光反射から作成し、色はXYZ(E)として求めたものをベースとして使用した。
分光反射のリファレンスはNoboru Ohtaタイプを使用した。
これを各レンダ空間用に値を変更してどの様に見えるかをテストする。

単体の色を見るだけなのでレンダ空間に対応した数値になっていればプレビュー結果は全く同じになるはず。
ライトに色がついていたりすると同じにはならないので注意。

各レンダ空間に適用するための変換マトリクス

ある標準光源に照らされたカラーチェッカーのXYZ値があったとする。
カラーチェッカーに照らされた光源色の色を相殺し、レンダ空間の白に合わせることをする。
これがディフューズ色。

XYZ値がE光源(D65環境下では少し赤い色)で照らされたものなら。(今回はこれ)
使用するレンダ空間レンダ空間に変更するためのmatrix(白色変更はbradfordを使用した)
scene-linear CIE XYZ
XYZ(E) → XYZ(D65)   Mayaではレンダ空間XYZの白色点はD65
ACEScg
XYZ(E) → ACESap1(D60)
Sharp RGB
XYZ(E) → Sharp RGB(E)
scene-linear Rec 709/sRGB
XYZ(E) → sRGB(D65)

カラーチャートのXYZ値がD65光源(D65環境下では白色)で照らされたものなら
使用するレンダ空間レンダ空間に変更するためのmatrix(白色変更はbradfordを使用した)
scene-linear CIE XYZ
XYZ(D65) → XYZ(D65)   Mayaではレンダ空間XYZの白色点はD65
ACEScg
XYZ(D65) → ACESap1(D60)
Sharp RGB
XYZ(D65) → Sharp RGB(E)
scene-linear Rec 709/sRGB
XYZ(D65) → sRGB(D65)

カラーチャートのXYZ値がA光源(D65環境下ではかなり赤い色)で照らされたものなら
使用するレンダ空間レンダ空間に変更するためのmatrix(白色変更はbradfordを使用した)
scene-linear CIE XYZ
XYZ(A) → XYZ(D65)  Mayaではレンダ空間XYZの白色点はD655
ACEScg
XYZ(A) → ACESap1(D60)
Sharp RGB
XYZ(A) → Sharp RGB(E)
scene-linear Rec 709/sRGB
XYZ(A) → sRGB(D65)

ということ
結果はぴったりと一致した
各レンダリング空間に値を合わせたので左のプレビュー画像は全く違いがない。
右側がプレビューのRaw(レンダ空間の色)なので、もし後からでレンダ空間を変えた場合これだけ数値を変えなければ色が合わないということがわかる


各色空間で入力した値
no-|-----------------XYZ to RGB value------------------|Linear 8bit Value
----
01 |0.119341058      0.0999           0.0559           |   30   25   14
02 |0.412222651      0.363180818      0.236403888      |  105   93   60
03 |0.182681943      0.187540862      0.317664563      |   47   48   81
04 |0.106503072      0.128926832      0.0611           |   27   33   16
05 |0.269627348      0.242756637      0.417069611      |   69   62  106
06 |0.320807381      0.417457527      0.406387316      |   82  106  104
----
07 |0.400687638      0.308497094      0.054292495      |  102   79   14
08 |0.134942682      0.114781053      0.340796394      |   34   29   87
09 |0.315580939      0.204426014      0.126666899      |   80   52   32
10 |0.0925           0.0663           0.137877016      |   24   17   35
11 |0.352064935      0.435275631      0.101625589      |   90  111   26
12 |0.502433902      0.44538134       0.0771           |  128  114   20
----
13 |0.0821           0.06             0.271971018      |   21   15   69
14 |0.149383905      0.230356768      0.0865           |   38   59   22
15 |0.229218256      0.129139309      0.0478           |   58   33   12
16 |0.607374032      0.607579034      0.08706536       |  155  155   22
17 |0.322739172      0.202413208      0.281472653      |   82   52   72
18 |0.143264706      0.18994647       0.357691497      |   37   48   91
----
19 |0.885095979      0.887271216      0.873774268      |  226  226  223
20 |0.584241934      0.583949023      0.581522196      |  149  149  148
21 |0.358099806      0.358176938      0.358332475      |   91   91   91
22 |0.203062932      0.203056127      0.20335156       |   52   52   52
23 |0.0922           0.092532056      0.094            |   24   24   24
24 |0.0335           0.0335           0.0351           |    9    9    9
レンダ空間変換マトリクス: 
[[ 0.95318743 -0.02659057  0.02387315]
 [-0.03824666  1.02884062  0.00940604]
 [ 0.00260677 -0.00303325  1.08925647]] 

レンダリング空間へ変換後のカラーチェッカーの値を表示
no-|-----------------XYZ to RGB value------------------|Linear 8bit Value
----
01 |0.112432506547   0.0987425789306  0.0608975105697  |   29   25   16
02 |0.388911966306   0.360112663437   0.257477419236   |   99   92   66
03 |0.176726964917   0.188950647697   0.345925534397   |   45   48   88
04 |0.099547799967   0.129146484173   0.0664401329774  |   25   33   17
05 |0.260507123966   0.24336851637    0.45426229032    |   66   62  116
06 |0.304390871004   0.421049945085   0.44223003515    |   78  107  113
----
07 |0.375023436398   0.302580056209   0.0592472055066  |   96   77   15
08 |0.133709456272   0.116135846678   0.371218284112   |   34   30   95
09 |0.29839591557    0.19944330473    0.138175313043   |   76   51   35
10 |0.089698440226   0.0659711936423  0.150223454509   |   23   17   38
11 |0.326435763181   0.435319837368   0.110293785651   |   83  111   28
12 |0.468911352206   0.439735202522   0.0839404536851  |  120  112   21
----
13 |0.0831540574969  0.0611485560525  0.296278213317   |   21   16   76
14 |0.138330568568   0.23210058722    0.0939113659824  |   35   59   24
15 |0.216195207607   0.124546543416   0.0522722679866  |   55   32   13
16 |0.564863939401   0.602690903976   0.0945768560331  |  144  154   24
17 |0.308968275525   0.198554778269   0.30682324801    |   79   51   78
18 |0.140046552638   0.193309707235   0.389415082802   |   36   49   99
----
19 |0.840929049484   0.887227458755   0.951380209782   |  214  226  243
20 |0.555247290974   0.58391499331    0.633178541245   |  142  149  161
21 |0.340366626166   0.358181351028   0.390163014021   |   87   91   99
22 |0.193012296386   0.203058645585   0.221415422808   |   49   52   56
23 |0.087667476106   0.0925585635666  0.102349780445   |   22   24   26
24 |0.031878942036   0.0335150496585  0.0382186153583  |    8    9   10
レンダ空間変換マトリクス: 
[[  1.01338130e+00  -2.16585679e-02   8.27726497e-03]
 [ -5.21145827e-01   1.42051414e+00   1.00631690e-01]
 [ -4.65451231e-04   2.06045382e-03   9.98404997e-01]] 

レンダリング空間へ変換後のカラーチェッカーの値を表示
no-|-----------------XYZ to RGB value------------------|Linear 8bit Value
----
01 |0.119237005144   0.085340579405   0.0559611312186  |   30   22   14
02 |0.411829528784   0.324865094702   0.236583270819   |  105   83   60
03 |0.183693992863   0.203167635234   0.317459276775   |   47   52   81
04 |0.105641592316   0.133787352243   0.0612186211054  |   27   34   16
05 |0.271429748061   0.246294487165   0.416779074121   |   69   63  106
06 |0.319422445356   0.466712333214   0.406449958721   |   81  119  104
----
07 |0.399817149166   0.234871338398   0.0546550417605  |  102   60   14
08 |0.137083259863   0.127018209804   0.340426514504   |   35   32   87
09 |0.316424704236   0.138673057551   0.126739187723   |   81   35   32
10 |0.0934430521552  0.0598488953814  0.137750655576   |   24   15   35
11 |0.348189758002   0.44506477052    0.102196492145   |   89  113   26
12 |0.500148977869   0.378587861896   0.0776608544617  |  128   97   20
----
13 |0.0841502671583  0.0698136788968  0.271622637056   |   21   18   69
14 |0.147109642146   0.258078888028   0.086767140788   |   38   66   22
15 |0.22988417592    0.0687982712984  0.0478831545127  |   59   18   12
16 |0.603062859793   0.555305699459   0.0878956760262  |  154  142   22
17 |0.325003686468   0.147661719492   0.281290546958   |   83   38   72
18 |0.144028513348   0.231154941979   0.357445671136   |   37   59   91
----
19 |0.884955154539   0.887046610962   0.873796807652   |  226  226  223
20 |0.584225766608   0.583552157926   0.581525930139   |  149  149  148
21 |0.358100061642   0.358232786954   0.358332262622   |   91   91   91
22 |0.203065468634   0.203082310515   0.203351085504   |   52   52   52
23 |0.092207707309   0.0928528272792  0.0939978131296  |   24   24   24
24 |0.0335132436565  0.0336610107017  0.0350974479765  |    9    9    9
レンダ空間変換マトリクス: 
[[ 1.2703 -0.0989 -0.1714]
 [-0.836   1.8     0.0361]
 [ 0.0297 -0.0315  1.0017]] 

レンダリング空間へ変換後のカラーチェッカーの値を表示
no-|-----------------XYZ to RGB value------------------|Linear 8bit Value
----
01 |0.132137575977   0.082068865512   0.0563926094226  |   34   21   14
02 |0.447208224262   0.317641516521   0.237608591577   |  114   81   61
03 |0.159065374843   0.196319137976   0.317722709311   |   41   50   81
04 |0.112067448677   0.145237439408   0.0603058160304  |   29   37   15
05 |0.24701325744    0.226609696629   0.418139727509   |   63   58  107
06 |0.296580280702   0.497899160192   0.403456241552   |   76  127  103
----
07 |0.469177410312   0.222279862902   0.0565675566291  |  120   57   14
08 |0.101653340871   0.106096563071   0.341767942356   |   26   27   87
09 |0.358954027538   0.10871383525    0.129815567176   |   92   28   33
10 |0.0873135594576  0.0469873602776  0.138770206927   |   22   12   35
11 |0.38676070107    0.492838533903   0.0985434986943  |   99  126   25
12 |0.580978631185   0.384434979928   0.0781238446794  |  148   98   20
----
13 |0.0517417975148  0.0491825537498  0.272981738731   |   13   13   70
14 |0.152153990166   0.29287988782    0.0838275137865  |   39   75   21
15 |0.270211152937   0.042549874184   0.0506211539697  |   69   11   13
16 |0.696534663683   0.589020629944   0.0861136402914  |  178  150   22
17 |0.341712491196   0.104694989381   0.285160493867   |   87   27   73
18 |0.101895127563   0.235047014826   0.356571220508   |   26   60   91
----
19 |0.886821389326   0.888691201431   0.873597991528   |  226  227  223
20 |0.584737065991   0.583674935852   0.581468374949   |  149  149  148
21 |0.358052298179   0.358282852931   0.358294630899   |   91   91   91
22 |0.203014134175   0.203081408764   0.203331958732   |   52   52   52
23 |0.0918586396616  0.0928719008     0.093983380236   |   23   24   24
24 |0.03322576       0.03356111       0.03509937       |    8    9    9
レンダ空間変換マトリクス: 
[[ 1.59421809 -0.36784581 -0.22637229]
 [-0.69051897  1.67230359  0.01821538]
 [ 0.01110683 -0.00669355  0.99558672]] 

レンダリング空間へ変換後のカラーチェッカーの値を表示
no-|-----------------XYZ to RGB value------------------|Linear 8bit Value
----
01 |0.140853667147   0.0856741038219  0.0563101127311  |   36   22   14
02 |0.470062979485   0.327007211708   0.237508089068   |  120   83   61
03 |0.150338286085   0.193266290868   0.317036323562   |   38   49   81
04 |0.108532583255   0.143175371883   0.0611502819076  |   28   37   16
05 |0.246134784699   0.227377079049   0.416598767454   |   63   58  106
06 |0.265882105058   0.483994638022   0.405362695423   |   68  123  103
----
07 |0.513013803894   0.240207340437   0.0564383152247  |  131   61   14
08 |0.095759477598   0.104976021859   0.340022856883   |   24   27   87
09 |0.399233715566   0.126255017773   0.128244650146   |  102   32   33
10 |0.0918654614507  0.0495122058275  0.137852125489   |   23   13   35
11 |0.37814875709    0.486656631552   0.102173872938   |   96  124   26
12 |0.619704256008   0.399277077953   0.0793590012333  |  158  102   20
----
13 |0.0472478561342  0.0486006641809  0.271280991564   |   12   12   69
14 |0.133833550409   0.283649659662   0.0862355284825  |   34   72   22
15 |0.307099942616   0.0585512710621  0.0492705325873  |   78   15   13
16 |0.725082087103   0.598239235659   0.0893602551585  |  185  153   23
17 |0.37634217002    0.120765945589   0.28246018119    |   96   31   72
18 |0.077552732294   0.225236653535   0.35643270505    |   20   57   91
----
19 |0.886858750119   0.888527406419   0.873809673648   |  226  227  223
20 |0.58496535427    0.583702556875   0.581536159464   |  149  149  148
21 |0.358018764043   0.358233032313   0.358330931811   |   91   91   91
22 |0.203000098116   0.203056809465   0.203350331714   |   52   52   52
23 |0.0916703846174  0.0927880861391  0.0939898334468  |   23   24   24
24 |0.0331378043934  0.0335291446171  0.0350929387467  |    8    9    9
レンダ空間変換マトリクス: 
[[ 3.14625105 -1.66612389 -0.48012709]
 [-0.99553498  1.9557634   0.03977154]
 [ 0.06359784 -0.21459655  1.1509987 ]] 

レンダリング空間へ変換後のカラーチェッカーの値を表示
no-|-----------------XYZ to RGB value------------------|Linear 8bit Value
----
01 |0.182192047191   0.0787957955525  0.0504924661917  |   46   20   13
02 |0.57834779706    0.309315831524   0.220379689894   |  147   79   56
03 |0.109777579585   0.197553298877   0.337004055536   |   28   50   86
04 |0.0909415610322  0.148552887374   0.0494321332625  |   23   38   13
05 |0.243606272226   0.222938590808   0.445099562254   |   62   57  114
06 |0.118687036829   0.513235833685   0.398568986358   |   30  131  102
----
07 |0.720602223536   0.206608064081   0.0217710494819  |  184   53    6
08 |0.069698517114   0.103698419806   0.376206652782   |   18   26   96
09 |0.591481583347   0.0906747914694  0.121994586508   |  151   23   31
10 |0.114365716636   0.0430637092733  0.15035131577    |   29   11   38
11 |0.333668342625   0.504844998478   0.045952843732   |   85  129   12
12 |0.80170489919    0.373936387857   0.0251184144145  |  204   95    6
----
13 |0.0277591226605  0.0464290882977  0.305383878631   |    7   12   78
14 |0.0446653586574  0.305246672161   0.0596281146441  |   11   78   15
15 |0.483066014644   0.0262722228225  0.0418826747792  |  123    7   11
16 |0.856846800313   0.587081469663   0.00845543155505 |  218  150    2
17 |0.54303032867    0.0857688107746  0.301062997749   |  138   22   77
18 |-0.0374650001358 0.243091269811   0.380051918148   |  -10   62   97
----
19 |0.886907677278   0.888899914601   0.871597903257   |  226  227  222
20 |0.586035814515   0.583560880458   0.58117437498    |  149  149  148
21 |0.357859605045   0.35825989882    0.358351054351   |   91   91   91
22 |0.202935703874   0.203061094993   0.203396602156   |   52   52   52
23 |0.090782530253   0.0929210084643  0.0942005393068  |   23   24   24
24 |0.0327317986319  0.0335636332703  0.035341597819   |    8    9    9

カラーチェッカー作成のPyMel
import pymel.core as pm
from numpy import *
    
#光源色(白色点)のXnYnZnの配列 (3*1mat)
arrMatLightXYZ = [
matrix('1.09850;1.00000;0.35585'),   #0.A
matrix('0.99072;1.00000;0.85223'),   #1.B
matrix('0.98074;1.00000;1.18232'),   #2.C
matrix('0.96422;1.00000;0.82521'),   #3.D50
matrix('0.95682;1.00000;0.92149'),   #4.D55
matrix('0.95047;1.00000;1.08883'),   #5.D65
matrix('0.94972;1.00000;1.22638'),   #6.D75
matrix('1.00000;1.00000;1.00000'),   #7.E
matrix('0.99186;1.00000;0.67393'),   #8.F2
matrix('0.95041;1.00000;1.08747'),   #9.F7
matrix('1.00962;1.00000;0.64350'),   #10.11
matrix('0.952646075;1.00000;1.008825184')] #11.D60
arrKeyLightXYZ = ["A","B","C","D50","D55","D65","D75","E","F2","F7","F11","D60"]
arrMatLightXYZ = dict(zip(arrKeyLightXYZ,arrMatLightXYZ))
    
#XYZtoRGBの配列  (3*3mat)
arrMatXYZ2RGB = [
matrix('1 0 0; 0 1 0; 0 0 1'), #ZYZ(E)
matrix('3.2404542 -1.5371385 -0.4985314;-0.969266 1.8760108 0.041556;0.0556434 -0.2040259 1.0572252'), #sRGB(D65)
matrix('1.64102338 -0.324803294 -0.236424695; -0.663662859 1.615331592 0.016756348; 0.011721894 -0.008284442 0.988394859'), #ACESap1(D60)
matrix('1.049811018 0 -9.74845E-05; -0.495903023 1.373313046 0.098240036; 0 0 0.991252018'), #ACESap0(D60)
matrix('1.2703 -0.0989 -0.1714; -0.836 1.8 0.0361; 0.0297 -0.0315 1.0017')] #SharpRGB(E)
arrKeyXYZ2RGB = ["XYZ","sRGB","ACESap1","ACESap0","SharpRGB"]
arrMatXYZ2RGB = dict(zip(arrKeyXYZ2RGB,arrMatXYZ2RGB))
    
#カラーチャートのディフューズの値XYZ(E) (3*1mat)
arrMatColorChecker = [
matrix('0.119341058; 9.99E-02; 5.59E-02'),       #no1
matrix('0.412222651; 0.363180818; 0.236403888'), #no2
matrix('0.182681943; 0.187540862; 0.317664563'), #no3
matrix('0.106503072; 0.128926832; 6.11E-02'),    #no4
matrix('0.269627348; 0.242756637; 0.417069611'), #no5
matrix('0.320807381; 0.417457527; 0.406387316'), #no6
matrix('0.400687638; 0.308497094; 0.054292495'), #no7
matrix('0.134942682; 0.114781053; 0.340796394'), #no8
matrix('0.315580939; 0.204426014; 0.126666899'), #no9
matrix('9.25E-02; 6.63E-02; 0.137877016'),       #no10
matrix('0.352064935; 0.435275631; 0.101625589'), #no11
matrix('0.502433902; 0.44538134; 7.71E-02'),     #no12
matrix('8.21E-02; 6.00E-02; 0.271971018'),       #no13
matrix('0.149383905; 0.230356768; 8.65E-02'),    #no14
matrix('0.229218256; 0.129139309; 4.78E-02'),    #no15
matrix('0.607374032; 0.607579034; 0.08706536'),  #no16
matrix('0.322739172; 0.202413208; 0.281472653'), #no17
matrix('0.143264706; 0.18994647; 0.357691497'),  #no18
matrix('0.885095979;0.887271216;0.873774268'),   #no19
matrix('0.584241934;0.583949023;0.581522196'),   #no20
matrix('0.358099806;0.358176938;0.358332475'),   #no21
matrix('0.203062932;0.203056127;0.20335156'),    #no22
matrix('9.22E-02;0.092532056;9.40E-02'),         #no23
matrix('3.35E-02;3.35E-02;3.51E-02')]           #no24

#bradford変換マトリクス(XYZtoLMS)
mBrad = matrix('0.8951 0.2664 -0.1614; -0.7502 1.7135 0.0367; 0.0389 -0.0685 1.0296')
    
#カラーチェッカーのsahpeを削除
def deleteColorCheckerMesh():
    oShapeList = pm.ls(type = 'shape')    #sahpeの一覧取得
    #sahpe親のtransformノードにアトリビュート'colorCheckerRoot'があったらそれ以下の使用マテリアルとノード削除
    for oShape in oShapeList:
        oParent = oShape.getParent()
        if oParent is not None:
            if oParent.hasAttr("colorCheckerRoot"):
                colPatchList = oParent.getChildren()
                for colPatch in colPatchList:
                    if len(colPatch.shadingGroups()) > 0:
                        sg = colPatch.shadingGroups()[0]
                        oShader = sg.surfaceShader.connections()[0]
                        pm.delete(oShader,sg)
                pm.delete(oParent)
                    
#カラーチェッカーのsahpeを作成しsahpeを返す
def createColorCheckerMesh():
    #黒の下地のshape作成
    baseTranse,baseShape = pm.polyPlane(name ='pPlane_base', height = 20.3, width = 28.8, sh = 1, sw = 1)
    baseTranse.addAttr('colorCheckerRoot', dt='string')
    shader , shadingEngine = pm.createSurfaceShader('lambert')
    shader.diffuse.set(1.0)
    pm.sets(shadingEngine,forceElement=baseTranse)
    shader.color.set(0.0,0.0,0.0)
        
    #24個のパッチ作成と新規マテリアル割り当て
    colPatchList = []
    for i in range(1, 25):
        patchTranse, patcShape= pm.polyPlane(name = 'pPlane_No' + str(i), height = 4, width = 4, sh = 1, sw = 1)
        patchTranse.translate.set(((i-1)%6)*4.5 - 11.25 ,0.1,floor((i-1)/6)*4.5 - 6.75)
        shader , shadingEngine = pm.createSurfaceShader('lambert')
        shader.diffuse.set(1.0)
        pm.sets(shadingEngine,forceElement=patchTranse)
        colPatchList.append(patchTranse)
    
    #下地の子供に24個のパッチ
    for colPatch in colPatchList:
        baseTranse.addChild(colPatch)
            
    return colPatchList
    
#マテリアルの色を設定する
def setColor(colPatchList,xyz2rgbColor):
    for i,colPatch in enumerate(colPatchList):
        sg = colPatch.shadingGroups()[0]
        oShader = sg.surfaceShader.connections()[0]
        oShader.color.set(xyz2rgbColor[i])
    
#カラーチェッカーの値XYZ(E)を意を任意のカラースペースに変換する関数(変換先の色空間、変換元の白色点、変換先の白色点を指定する)
def ColorChange(XYZtoRGBname,sorceWname,distWname):
    print '使用するXYZtoRGBMatrix :',XYZtoRGBname,'\n',arrMatXYZ2RGB[XYZtoRGBname],'\n'
    print '変換元白色点 :',sorceWname,"\n ",arrMatLightXYZ[sorceWname],'\n'
    print '変換先白色点 :',distWname,"\n ",arrMatLightXYZ[distWname],'\n'
    
    #LMSスケールを求める
    lmsS = mBrad * arrMatLightXYZ[sorceWname]
    lmsD = mBrad * arrMatLightXYZ[distWname]
    mScale = matrix(zeros((3, 3)))     #対角行列の入れ物
    fill_diagonal(mScale,(lmsD/lmsS))  #対角行列を作成
    print "LMSスケール: \n",mScale,'\n'
                        
    #白色点変換マトリクス
    mChangeW = mBrad.I* mScale * mBrad
    print "白色点変換マトリクス: \n",mChangeW,'\n'
        
    #レンダ空間変換マトリクス(from XYZ)
    mRenderSpace = arrMatXYZ2RGB[XYZtoRGBname] * mChangeW
    print "レンダ空間変換マトリクス: \n",mRenderSpace,'\n'
        
    #変換後のカラーを格納する配列
    distCol = empty((24,3),dtype = float64)
    for i,elem in enumerate(arrMatColorChecker):
        arrCol = mRenderSpace * elem
        distCol[i] = (arrCol.T)
            
    return distCol
    
#shape削除
deleteColorCheckerMesh()
    
#shape作成
colPatchList = createColorCheckerMesh()
    
# 色変換
#白色点はここから選ぶ : A B C D50 D55 D65 D75 E F2 F7 F11 D60
#XYZtoRGB変換はここから選ぶ : XYZ sRGB ACESap1 ACESap0 SharpRGB"
XYZtoRGBname,sorceWname,distWname = 'ACESap1',"E","D60"
xyz2rgbColor = ColorChange (XYZtoRGBname,sorceWname,distWname)  #カラースペースに変換する関数を実行
    
#変換値のログ表示
print 'レンダリング空間へ変換後のカラーチェッカーの値を表示'
print '{:^3}|{:-^51}|{:^17}'.format('no','XYZ to RGB value','Linear 8bit Value')
for i,colPatch in enumerate(xyz2rgbColor):
    if (i)%6 == 0:
        print "----"
    val8 = around(xyz2rgbColor[i] * array([255, 255, 255])).astype(int)
    print str(i+1).zfill(2),'|{:< 17}{:< 17}{:< 17}|{:>5}{:>5}{:>5}'.format(xyz2rgbColor[i][0],xyz2rgbColor[i][1],xyz2rgbColor[i][2],val8[0],val8[1],val8[2])
    
#色をセット
xyz2rgbColor = xyz2rgbColor.tolist() #配列からリストへ変換
setColor(colPatchList,xyz2rgbColor)  #setColor関数でlambertのカラーを設定
    
#プレファレンスのレンダリング設定も連動して変更する場合
strRenderSpaceList = ["scene-linear CIE XYZ","scene-linear Rec 709/sRGB","ACEScg","ACES2065-1","Sharp RGB"]
index = arrKeyXYZ2RGB.index(XYZtoRGBname)
pm.colorManagementPrefs(e=True,rsn = strRenderSpaceList[index])

149行目の3個の変数のうち1つ目と3つ目を指定して実行(maya2016にnumpyを入れた環境で確認)
XYZtoRGBname,sorceWname,distWname = 'ACESap1',"E","D60"
#XYZtoRGBname:変換するレンダ空間 XYZ sRGB ACESap1 ACESap0 SharpRGB
#sorceWname:変換前のXYZホワイトバランス(今回のリファレンスカラーはEで作成しているのでE)
#distWname:変換先のな白色点(基本はレンダ空間のネイティブな白色点)でここから選ぶ : A B C D50 D55 D65 D75 E F2 F7 F11 D60
from numpy import *
   
#光源の色XnYnZnの配列 (3*1mat)
arrMatLightXYZ = [
matrix('1.09850;1.00000;0.35585'),   #0.A
matrix('0.99072;1.00000;0.85223'),   #1.B
matrix('0.98074;1.00000;1.18232'),   #2.C
matrix('0.96422;1.00000;0.82521'),   #3.D50
matrix('0.95682;1.00000;0.92149'),   #4.D55
matrix('0.95047;1.00000;1.08883'),   #5.D65
#matrix('0.950455927;1.00000;1.089057751'),#5.D65 mayaではこちらが使われていると思われる
matrix('0.94972;1.00000;1.22638'),   #6.D75
matrix('1.00000;1.00000;1.00000'),   #7.E
matrix('0.99186;1.00000;0.67393'),   #8.F2
matrix('0.95041;1.00000;1.08747'),   #9.F7
matrix('1.00962;1.00000;0.64350'),   #10.11
matrix('0.952646075;1.00000;1.008825184')] #11.D60
arrKeyLightXYZ = ["A","B","C","D50","D55","D65","D75","E","F2","F7","F11","D60"]
arrMatLightXYZ = dict(zip(arrKeyLightXYZ,arrMatLightXYZ))
    
#XYZtoRGBの配列  (3*3mat)
arrMatXYZ2RGB = [
matrix('1 0 0; 0 1 0; 0 0 1'), #ZYZ(E)
matrix('3.2404542 -1.5371385 -0.4985314;-0.969266 1.8760108 0.041556;0.0556434 -0.2040259 1.0572252'), #sRGB(D65)
matrix('1.64102338 -0.324803294 -0.236424695; -0.663662859 1.615331592 0.016756348; 0.011721894 -0.008284442 0.988394859'), #ACESap1(D60)
matrix('1.049811018 0 -9.74845E-05; -0.495903023 1.373313046 0.098240036; 0 0 0.991252018'), #ACESap0(D60)
matrix('1.2703 -0.0989 -0.1714; -0.836 1.8 0.0361; 0.0297 -0.0315 1.0017')] #SharpRGB(E)
arrKeyXYZ2RGB = ["XYZ","sRGB","ACESap1","ACESap0","SharpRGB"]
arrMatXYZ2RGB = dict(zip(arrKeyXYZ2RGB,arrMatXYZ2RGB))
    
#カラーチャートのディフューズの値XYZ(E) (3*1mat)
arrMatColorChecker = [
matrix('0.119341058; 9.99E-02; 5.59E-02'),       #no1
matrix('0.412222651; 0.363180818; 0.236403888'), #no2
matrix('0.182681943; 0.187540862; 0.317664563'), #no3
matrix('0.106503072; 0.128926832; 6.11E-02'),    #no4
matrix('0.269627348; 0.242756637; 0.417069611'), #no5
matrix('0.320807381; 0.417457527; 0.406387316'), #no6
matrix('0.400687638; 0.308497094; 0.054292495'), #no7
matrix('0.134942682; 0.114781053; 0.340796394'), #no8
matrix('0.315580939; 0.204426014; 0.126666899'), #no9
matrix('9.25E-02; 6.63E-02; 0.137877016'),       #no10
matrix('0.352064935; 0.435275631; 0.101625589'), #no11
matrix('0.502433902; 0.44538134; 7.71E-02'),     #no12
matrix('8.21E-02; 6.00E-02; 0.271971018'),       #no13
matrix('0.149383905; 0.230356768; 8.65E-02'),    #no14
matrix('0.229218256; 0.129139309; 4.78E-02'),    #no15
matrix('0.607374032; 0.607579034; 0.08706536'),  #no16
matrix('0.322739172; 0.202413208; 0.281472653'), #no17
matrix('0.143264706; 0.18994647; 0.357691497'),  #no18
matrix('0.885095979;0.887271216;0.873774268'),   #no19
matrix('0.584241934;0.583949023;0.581522196'),   #no20
matrix('0.358099806;0.358176938;0.358332475'),   #no21
matrix('0.203062932;0.203056127;0.20335156'),    #no22
matrix('9.22E-02;0.092532056;9.40E-02'),         #no23
matrix('3.35E-02;3.35E-02;3.51E-02')]           #no24
    
#bradford変換マトリクス(XYZtoLMS)
mBrad = matrix('0.8951 0.2664 -0.1614; -0.7502 1.7135 0.0367; 0.0389 -0.0685 1.0296')
#cat02
#mBrad = matrix('0.7328 0.4296 -0.1624; -0.7036 1.6975 0.0061; 0.003 0.0136 0.9834') #mayaではこちらが使われていると思われる
    
#カラーチェッカーの値XYZ(E)を意を任意のカラースペースに変換する関数(変換先の色空間、変換元の白色点、変換先の白色点を指定する)
def ColorChange(XYZtoRGBname,sorceWname,distWname):
    print '使用するXYZtoRGBMatrix :',XYZtoRGBname,'\n',arrMatXYZ2RGB[XYZtoRGBname],'\n'
    print '変換元白色点 :',sorceWname,"\n ",arrMatLightXYZ[sorceWname],'\n'
    print '変換先白色点 :',distWname,"\n ",arrMatLightXYZ[distWname],'\n'
    
    #LMSスケールを求める
    lmsS = mBrad * arrMatLightXYZ[sorceWname]
    lmsD = mBrad * arrMatLightXYZ[distWname]
    mScale = matrix(zeros((3, 3)))     #対角行列の入れ物
    fill_diagonal(mScale,(lmsD/lmsS))  #対角行列を作成
    print "LMSスケール: \n",mScale,'\n'
                        
    #白色点変換マトリクス
    mChangeW = mBrad.I* mScale * mBrad
    print "白色点変換マトリクス: \n",mChangeW,'\n'
        
    #レンダ空間変換マトリクス(from XYZ)
    mRenderSpace = arrMatXYZ2RGB[XYZtoRGBname] * mChangeW
    print "レンダ空間変換マトリクス: \n",mRenderSpace,'\n'
        
    #変換後のカラーを格納する配列
    distCol = empty((24,3),dtype = float64)
    for i,elem in enumerate(arrMatColorChecker):
        arrCol = mRenderSpace * elem
        distCol[i] = (arrCol.T)
            
    return distCol
    
# 色変換
#白色点はここから選ぶ : A B C D50 D55 D65 D75 E F2 F7 F11 D60
#XYZtoRGB変換はここから選ぶ : XYZ sRGB ACESap1 ACESap0 SharpRGB"
xyz2rgbColor = ColorChange (XYZtoRGBname="ACESap1",sorceWname="E",distWname="D60")
    
print 'レンダリング空間へ変換後のカラーチェッカーの値を表示'
print '{:-^3}|{:-^51}|{:-^17}'.format('no','XYZ to RGB value','Linear 8bit Value')
for i,colPatch in enumerate(xyz2rgbColor):
    if (i)%6 == 0:
        print "----"
    val8 = around(xyz2rgbColor[i] * array([255, 255, 255])).astype(int)
    print str(i+1).zfill(2),'|{:< 17}{:< 17}{:< 17}|{:>5}{:>5}{:>5}'.format(xyz2rgbColor[i][0],xyz2rgbColor[i][1],xyz2rgbColor[i][2],val8[0],val8[1],val8[2])


Mayaで使われているものと少し誤差があった (9/19追記)

Mayaで使われている色管理のデータはここにあるみたい
C:\Program Files\Autodesk\Maya2016\synColor

例えば
C:\Program Files\Autodesk\Maya2016\synColor\transforms\primaries
CIE-XYZ_to_ACES.ctf

これはXYZ(D65)からACESプライマリに変換するマトリクスが記述されている
[ 1.062366127968  0.008406953886 -0.016655789688]
[-0.493941366673  1.371109485626  0.090316586196]
[-0.000334668584 -0.001037458307  0.919469654560]

スクリプトで今回求めた変換マトリクスがMayaで使われているものと少しだけ誤差があった
xyz2rgbColor = ColorChange (XYZtoRGBname="ACESap0",sorceWname="D65",distWname="D60")
として実行すると下のようになり少し値が違った

[ 1.06344949  0.00638714 -0.01576369]
[-0.49208912  1.36824527  0.09135557]
[-0.00280919  0.00463247  0.91661469]

白色点変更はbradfordではなくてcat02みたい
bradfordではなくcat02を使った白色点変更にすると近づいた
さらにD65の値をx:0.3127 y:0.329から求めたXnYnZnにしたらもっと近づいた。

[  1.06236611e+00   8.40695406e-03  -1.66557898e-02]
[ -4.93941371e-01   1.37110952e+00   9.03165869e-02]
[ -3.34668584e-04  -1.03745828e-03   9.19469647e-01]

15/9/24追記
やはりcat02みたい
↓Mayaのインストール場所のファイルに書いてあった
C:\Program Files\Autodesk\Maya2016\synColor\transforms\whitepoint


カラーチェッカー作成のPyMel(修正)
白色変更をbradfordからcat02タイプに変更
import pymel.core as pm
from numpy import *
    
#光源色(白色点)のXnYnZnの配列 (3*1mat)
arrMatLightXYZ = [
matrix('1.09850;1.00000;0.35585'),   #0.A
matrix('0.99072;1.00000;0.85223'),   #1.B
matrix('0.98074;1.00000;1.18232'),   #2.C
matrix('0.96422;1.00000;0.82521'),   #3.D50
matrix('0.95682;1.00000;0.92149'),   #4.D55
#matrix('0.95047;1.00000;1.08883'),  #5.D65
matrix('0.950455927;1.00000;1.089057751'),#5.D65 mayaではこちらが使われていると思われる
matrix('0.94972;1.00000;1.22638'),   #6.D75
matrix('1.00000;1.00000;1.00000'),   #7.E
matrix('0.99186;1.00000;0.67393'),   #8.F2
matrix('0.95041;1.00000;1.08747'),   #9.F7
matrix('1.00962;1.00000;0.64350'),   #10.11
matrix('0.952646075;1.00000;1.008825184')] #11.D60
arrKeyLightXYZ = ["A","B","C","D50","D55","D65","D75","E","F2","F7","F11","D60"]
arrMatLightXYZ = dict(zip(arrKeyLightXYZ,arrMatLightXYZ))
    
#XYZtoRGBの配列  (3*3mat)
arrMatXYZ2RGB = [
matrix('1 0 0; 0 1 0; 0 0 1'), #ZYZ(E)
matrix('3.2404542 -1.5371385 -0.4985314;-0.969266 1.8760108 0.041556;0.0556434 -0.2040259 1.0572252'), #sRGB(D65)
matrix('1.64102338 -0.324803294 -0.236424695; -0.663662859 1.615331592 0.016756348; 0.011721894 -0.008284442 0.988394859'), #ACESap1(D60)
matrix('1.049811018 0 -9.74845E-05; -0.495903023 1.373313046 0.098240036; 0 0 0.991252018'), #ACESap0(D60)
matrix('1.2703 -0.0989 -0.1714; -0.836 1.8 0.0361; 0.0297 -0.0315 1.0017')] #SharpRGB(E)
arrKeyXYZ2RGB = ["XYZ","sRGB","ACESap1","ACESap0","SharpRGB"]
arrMatXYZ2RGB = dict(zip(arrKeyXYZ2RGB,arrMatXYZ2RGB))
    
#カラーチャートのディフューズの値XYZ(E) (3*1mat)
arrMatColorChecker = [
matrix('0.119341058; 9.99E-02; 5.59E-02'),       #no1
matrix('0.412222651; 0.363180818; 0.236403888'), #no2
matrix('0.182681943; 0.187540862; 0.317664563'), #no3
matrix('0.106503072; 0.128926832; 6.11E-02'),    #no4
matrix('0.269627348; 0.242756637; 0.417069611'), #no5
matrix('0.320807381; 0.417457527; 0.406387316'), #no6
matrix('0.400687638; 0.308497094; 0.054292495'), #no7
matrix('0.134942682; 0.114781053; 0.340796394'), #no8
matrix('0.315580939; 0.204426014; 0.126666899'), #no9
matrix('9.25E-02; 6.63E-02; 0.137877016'),       #no10
matrix('0.352064935; 0.435275631; 0.101625589'), #no11
matrix('0.502433902; 0.44538134; 7.71E-02'),     #no12
matrix('8.21E-02; 6.00E-02; 0.271971018'),       #no13
matrix('0.149383905; 0.230356768; 8.65E-02'),    #no14
matrix('0.229218256; 0.129139309; 4.78E-02'),    #no15
matrix('0.607374032; 0.607579034; 0.08706536'),  #no16
matrix('0.322739172; 0.202413208; 0.281472653'), #no17
matrix('0.143264706; 0.18994647; 0.357691497'),  #no18
matrix('0.885095979;0.887271216;0.873774268'),   #no19
matrix('0.584241934;0.583949023;0.581522196'),   #no20
matrix('0.358099806;0.358176938;0.358332475'),   #no21
matrix('0.203062932;0.203056127;0.20335156'),    #no22
matrix('9.22E-02;0.092532056;9.40E-02'),         #no23
matrix('3.35E-02;3.35E-02;3.51E-02'),            #no24
matrix('0.037;0.037;0.037')]                     #mount 台紙の色(適当)
    
#bradford変換マトリクス(XYZtoLMS)
#mBrad = matrix('0.8951 0.2664 -0.1614; -0.7502 1.7135 0.0367; 0.0389 -0.0685 1.0296')
#cat02
mBrad = matrix('0.7328 0.4296 -0.1624; -0.7036 1.6975 0.0061; 0.003 0.0136 0.9834') #mayaではこちらが使われていると思われる
 
#カラーチェッカーのsahpeを削除
def deleteColorCheckerMesh():
    oShapeList = pm.ls(type = 'shape')    #sahpeの一覧取得
    #sahpe親のtransformノードにアトリビュート'colorCheckerRoot'があったらそれ以下の使用マテリアルとノード削除
    for oShape in oShapeList:
        oParent = oShape.getParent()
        if oParent is not None:
            if oParent.hasAttr("colorCheckerRoot"):
                colPatchList = oParent.getChildren()
                for colPatch in colPatchList:
                    if len(colPatch.shadingGroups()) > 0:
                        sg = colPatch.shadingGroups()[0]
                        oShader = sg.surfaceShader.connections()[0]
                        pm.delete(oShader,sg)
                pm.delete(oParent)
                    
#カラーチェッカーのsahpeを作成しsahpeを返す
def createColorCheckerMesh():
    #黒の下地のshape作成
    baseTranse,baseShape = pm.polyPlane(name ='pPlane_base', height = 20.3, width = 28.8, sh = 1, sw = 1)
    baseTranse.addAttr('colorCheckerRoot', dt='string')
    shader , shadingEngine = pm.createSurfaceShader('lambert')
    shader.diffuse.set(1.0)
    pm.sets(shadingEngine,forceElement=baseTranse)
    shader.color.set(0.0,0.0,0.0)
        
    #24個のパッチ作成と新規マテリアル割り当て
    colPatchList = []
    for i in range(1, 25):
        patchTranse, patcShape= pm.polyPlane(name = 'pPlane_No' + str(i), height = 4, width = 4, sh = 1, sw = 1)
        patchTranse.translate.set(((i-1)%6)*4.5 - 11.25 ,0.1,floor((i-1)/6)*4.5 - 6.75)
        shader , shadingEngine = pm.createSurfaceShader('lambert')
        shader.diffuse.set(1.0)
        pm.sets(shadingEngine,forceElement=patchTranse)
        colPatchList.append(patchTranse)
    
    #下地の子供に24個のパッチ
    for colPatch in colPatchList:
        baseTranse.addChild(colPatch)
        
    colPatchList.append(baseTranse)   #台紙も配列の最後に加える
    return colPatchList
    
#マテリアルの色を設定する
def setColor(colPatchList,xyz2rgbColor):
    for i,colPatch in enumerate(colPatchList):
        sg = colPatch.shadingGroups()[0]
        oShader = sg.surfaceShader.connections()[0]
        oShader.color.set(xyz2rgbColor[i])
    
#カラーチェッカーの値XYZ(E)を意を任意のカラースペースに変換する関数(変換先の色空間、変換元の白色点、変換先の白色点を指定する)
def ColorChange(XYZtoRGBname,sorceWname,distWname):
    print '使用するXYZtoRGBMatrix :',XYZtoRGBname,'\n',arrMatXYZ2RGB[XYZtoRGBname],'\n'
    print '変換元白色点 :',sorceWname,"\n ",arrMatLightXYZ[sorceWname],'\n'
    print '変換先白色点 :',distWname,"\n ",arrMatLightXYZ[distWname],'\n'
    
    #LMSスケールを求める
    lmsS = mBrad * arrMatLightXYZ[sorceWname]
    lmsD = mBrad * arrMatLightXYZ[distWname]
    mScale = matrix(zeros((3, 3)))     #対角行列の入れ物
    fill_diagonal(mScale,(lmsD/lmsS))  #対角行列を作成
    print "LMSスケール: \n",mScale,'\n'
                        
    #白色点変換マトリクス
    mChangeW = mBrad.I* mScale * mBrad
    print "白色点変換マトリクス: \n",mChangeW,'\n'
        
    #レンダ空間変換マトリクス(from XYZ)
    mRenderSpace = arrMatXYZ2RGB[XYZtoRGBname] * mChangeW
    print "レンダ空間変換マトリクス: \n",mRenderSpace,'\n'
        
    #変換後のカラーを格納する配列
    distCol = empty((25,3),dtype = float64)
    for i,elem in enumerate(arrMatColorChecker):
        arrCol = mRenderSpace * elem
        distCol[i] = (arrCol.T)
            
    return distCol
    
#shape削除
deleteColorCheckerMesh()
    
#shape作成
colPatchList = createColorCheckerMesh()
    
# 色変換
#白色点はここから選ぶ : A B C D50 D55 D65 D75 E F2 F7 F11 D60
#XYZtoRGB変換はここから選ぶ : XYZ sRGB ACESap1 ACESap0 SharpRGB"
XYZtoRGBname,sorceWname,distWname = 'ACESap0',"E","D60"
xyz2rgbColor = ColorChange (XYZtoRGBname,sorceWname,distWname)  #カラースペースに変換する関数を実行
    
#変換値のログ表示
print 'レンダリング空間へ変換後のカラーチェッカーの値を表示'
print '{:^3}|{:-^51}|{:^17}'.format('no','XYZ to RGB value','Linear 8bit Value')
for i,colPatch in enumerate(xyz2rgbColor):
    if i<=23:
        if (i)%6 == 0:
            print "----"
        val8 = around(xyz2rgbColor[i] * array([255, 255, 255])).astype(int)
        print str(i+1).zfill(2),'|{:< 17}{:< 17}{:< 17}|{:>5}{:>5}{:>5}'.format(xyz2rgbColor[i][0],xyz2rgbColor[i][1],xyz2rgbColor[i][2],val8[0],val8[1],val8[2])
    
#色をセット
xyz2rgbColor = xyz2rgbColor.tolist() #配列からリストへ変換
setColor(colPatchList,xyz2rgbColor)  #setColor関数でlambertのカラーを設定
    
#プレファレンスのレンダリング設定も連動して変更する場合
strRenderSpaceList = ["scene-linear CIE XYZ","scene-linear Rec 709/sRGB","ACEScg","ACES2065-1","Sharp RGB"]
index = arrKeyXYZ2RGB.index(XYZtoRGBname)
pm.colorManagementPrefs(e=True,rsn = strRenderSpaceList[index])


2015年9月11日金曜日

Mayaスタディ PyMelとNumPy

引き続きレンダリング空間について調査中だがカラーチェッカーをスクリプトで作りたいと思っていたのでmayaのスクリプトも勉強中。

Melを今から覚えるのは抵抗があるし、行列を扱いたいのでPythonとNumpyで行こうと思う。

MelをPythonに移植したmaya.cmdではなく、PyMelを使用してみる。
PyMelはSIのpythonスクリプトのようにオブジェクトが帰ってくるので使いやすそう。
ただMaya自体よくわかっていないので習得には時間が掛かるかも。

PyMelメモ

参考
PyMEL for Maya — PyMEL 1.0.7 documentatio
mtazmi-Lab: [pymel] pymel始めました
PyMEL Tips



選択したものの名前表示

from pymel.core import *

#plane3を選択して実行
a = selected()[0]
print a.longName()    #|pPlane1|pPlane2|pPlane3
print a.name()   #pPlane3
#Mayaでの名前は階層になっている

名前から選択する

from pymel.core import *

select(clear=True)                     #選択を解除する
select('|pPlane1|pPlane2|pPlane3')     #選択する
select('|pPlane1|pPlane2|', add=True)  #追加選択する 

print selected()                       #選択されているものを表示
#[nt.Transform(u'pPlane3'), nt.Transform(u'pPlane2')]

オブジェクトをリストに追加

from pymel.core import *

objList = []                                #空のリスト作成
objList.append(PyNode('pPlane1'))           #オブジェクトを追加
objList.append(PyNode('|pPlane1|pPlane2'))  #オブジェクトを追加

#リストを表示
print objList
#[nt.Transform(u'pPlane1'), nt.Transform(u'pPlane2')]

アトリビュートとメソッドの一覧

from pymel.core import *
a = selected()[0]
print listAttr(a)  # 指定オブジェクトのアトリビュート一覧
print dir(a)       # 指定オブジェクトのメソッド一覧

位置の設定と位置の取得

from pymel.core import *

tf,sh = polyPlane()
tf.translate.set(0,2,0)           #移動値のセット

tf2,sh2 = polyPlane()
tf2.setParent(tf)

print tf2.attr("translate").get() #アトリビュートのtranslateから位置を取得
#[0.0, -2.0, 0.0]
print tf2.translate.get()         #アトリビュートのtranslateから位置を取得
#[0.0, -2.0, 0.0]

print tf2.getTranslation()        #getTranslation()メソッドで位置を取得
#[0.0, -2.0, 0.0]
print tf2.getTranslation('world') #getTranslation()メソッドで位置を取得(world)
#[0.0, 0.0, 0.0]

tm = tf2.getTransformation()      #TransformationMatrixを取得
print tm
#[[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, -2.0, 0.0, 1.0]]
print tf2.getTranslation('world') #TransformationMatrixから移動値を取得
#[0.0, 0.0, 0.0]

アトリビュートの追加と取得

from pymel.core import *

oTransf,oShape = polyPlane()

#floatのattr追加、セット、取得
oTransf.addAttr('attr1', at='float')
oTransf.setAttr('attr1', 2.0)
print transf.attr1.get()
#2.0

#文字列のatrr追加、セット、取得
oTransf.addAttr('attr2', dt='string')
oTransf.setAttr('attr2',"aaaaa")
print transf.attr2.get()
#aaaaa

#matrixのatrr追加、セット、取得
oTransf.addAttr('attr3', at='matrix')
oTransf.setAttr('attr3', [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16])
print transf.attr3.get()
#[[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0], [9.0, 10.0, 11.0, 12.0], [13.0, 14.0, 15.0, 16.0]]

#float3のatrr追加、セット、取得
oTransf.addAttr('attr4', dt='float3')
oTransf.setAttr('attr4', [1,2,3])
print transf.attr4.get()
#(1.0, 2.0, 3.0)

#ベクター配列のatrr追加、セット、取得
oTransf.addAttr('attr5', dt='vectorArray')
oTransf.setAttr('attr5', [[1,2,3],[4,5,6],[7,8,9]])
print transf.attr5.get()
#[dt.Vector([1.0, 2.0, 3.0]), dt.Vector([4.0, 5.0, 6.0]), dt.Vector([7.0, 8.0, 9.0])]

#アトリビュートの存在を調べる
print oTransf.hasAttr("attr5"), oTransf.hasAttr("attr100")
#True False

#アトリビュートの削除
oTransf.deleteAttr("attr5")

子供にする

from pymel.core import *
  
a = PyNode('pPlane1')                    #親にしたいやつをオブジェクトにする
b = PyNode('|pPlane1|pPlane2|pPlane3')   #子供にしたいやつをオブジェクトにする
a.addChild(b)

print b.longName()
#|pPlane1|pPlane3a

親にする

from pymel.core import *

a = PyNode('pPlane1')                  #親にしたいやつをオブジェクトにする
b = PyNode('|pPlane1|pPlane2|pPlane3') #子供をオブジェクトにする

b.setParent(a)                         #親をセットする
print b.longName()
#|pPlane1|pPlane3

親を取得

from pymel.core import *
 
a = PyNode('|pPlane1|pPlane2|pPlane3')    #オブジェクトを取得
print a.getParent()                       #親を取得 #pPlane2
print a.getParent().getParent()           #親の親を取得 #pPlane1
 
#ちなみにこれでも行けた
print a.getParent(0)     #自分を取得 #pPlane3
print a.getParent(1)     #親を取得 #pPlane2
print a.getParent(2)     #親の親を取得 #pPlane1

#親をすべて取得する場合はこれ
parentsList = a.getAllParents()
print parentsList    #[nt.Transform(u'pPlane2'), nt.Transform(u'pPlane1')]

マテリアル作成と割り当て

from pymel.core import *

#ランバートのマテリアルを新しく作って、一個選択されているものに割り当てる
sel = selected()[0]
shader , shadingEngine = createSurfaceShader("lambert")
sets(shadingEngine,forceElement=sel)

print shader
#lambert2
print shadingEngine
#lambert2SG
'''
SurfaceShaderというのはSIのマテリアルのsurfaceに指すシェーダーのようなもの?
[シェーダー名SG]というのは何?マテリアル?
'''

使用しているマテリアルの取得

上のシーンでpPlane2に新規ランバートを割り当て、pPlane2を選択して実行した
from pymel.core import *

#シェイプで使用しているSG?というものが取得できる
oShape = selected()[0].getShape()
sg = oShape.outputs(type='shadingEngine')

print sg[0]
#lambert2SG

'''
lambert2SGというのが取得できる
ハイパーグラフで見るとシェイプの先にlambert2SGに繋がっているのでoutputsプロパティで取得できる。
多分SGはシェーディンググループのことで、サーフェイス、ボリュームディスプレイスを入力に持つマテリアルのこと。
シェーディングエンジンってシェーディンググループと同じこと?
'''

sg = oShape.shadingGroups()
print sg[0]
#lambert2SG
'''
これでも同じものがとれた
'''

#SGが繋がっているものを取得してみる
oConnections = sg[0].connections()
for elem in oConnections:
    print elem

'''
lightLinker1
materialInfo1
lightLinker1
renderPartition
lambert2
pPlane3
pPlane2
'''
#SGが共有されているシェイプのトランスフォームノードも含まれている

#下記はSGのサーフェイスシェーダーに接続されているものを取得する方法
print sg[0].surfaceShader.connections()[0]
#lambert2



子供を取得

from pymel.core import *

obj = PyNode('pPlane1')
oChildren = obj.getChildren()
for Child in oChildren:
    print Child

'''
pPlaneShape1
pPlane2
pPlane3

pPlaneShape1ってなんだ?
nodeTypeというのを確認
'''
for Child in oChildren:
    print Child.nodeType()

'''
mesh
transform
transform

pPlaneShape1はmeshというノードタイプらしい。
それ以外は
mayaの場合これらも自身の子供として取得されてしまう。
なのでノードタイプでマスクする必要がある。
(getChildren()でマスク機能はないのかな?)
'''
for Child in oChildren:
    if Child.nodeType() == "transform":
        print Child
'''
pPlane2
pPlane3
'''

子孫を取得

#一つ選択してその子孫をノードタイプを指定して取得(ここではpPlane1選択後に実行)
from pymel.core import *

def getDescendants(obj,nType):
    oChildren = obj.getChildren()
    for Child in oChildren:
        if Child.nodeType() == nType:
            objList.append(Child)
        getDescendants(Child,nType)
    return objList

obj = selected()[0]
objList = []
print getDescendants(obj,"transform")
#[nt.Transform(u'pPlane2'), nt.Transform(u'pPlane4'), nt.Transform(u'pPlane5'), nt.Transform(u'pPlane3')]

削除

複数オブジェクトの削除の例

from pymel.core import *

objs = [PyNode('pPlane1'),PyNode('pPlane3')]
delete(objs)

matrixを作成

import pymel.core as pm

m = pm.datatypes.Matrix([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])
#or
m = pm.datatypes.Matrix(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)

PyMelMatrix to NumPyMatrix

import pymel.core as pm
import numpy as np

#PymelMatrix
m = pm.datatypes.Matrix([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])
#toNymPyMatrix
a = pm.datatypes.Matrix([[m[0,0],m[0,1],m[0,2],m[0,3]],
                         [m[1,0],m[1,1],m[1,2],m[1,3]],
                         [m[2,0],m[2,1],m[2,2],m[2,3]],
                         [m[3,0],m[3,1],m[3,2],m[3,3]]])


NumPyメモ


NumpyをMayaのPythonで使えるようにする
[GUIDE] Numpy+Scipy for Maya Windows 64 bit
このページのリンク先のNumpyを解凍して"\ProgramFiles\Autodesk\Maya2016\Python\Lib\site-packages"に入れただけ


参考
私訳「暫定的 NumPy チュートリアル」 - naoya_t@hatenablog
良いもの。悪いもの。: SciPyの使い方: 行列演算
python/numpy - 機械学習の「朱鷺の杜Wiki
NumpyとScipy

モジュールをインポートする書き方

#安全性◎ 手間× | 都度numpy.を付ける
import numpy
a = numpy.array([1,2,3])

#安全性◎ 手間○ | 任意の省略文字に置き換える。この場合都度np.を付ける(よく使われている)
import numpy as np
a = np.array([1,2,3])

#安全性× 手間◎ | 他モジュールと名前の衝突が起こる可能性が或る
from numpy import *
a = array([1,2,3])

#安全性〇 手間◎ | 衝突を避けるため必要なものを部分的にしか読み込まない。
from numpy import array,linalg
a = array([1,2,3])
length = norm(a)

Numpyの配列

numpy.array(リスト)
from numpy import *
 
arr = array( [0, 1, 2, 3, 4, 5] )    #0,1,2...5までの配列を作る
arr = array( [0, 1, 2, 3, 4, 5], dtype=int64 ) #dtypeを指定する場合
print arr                 #[0 1 2 3 4 5]
print len(arr)            #配列の要素数 #6
print arr[3]              #3番目の要素 #3
print arr[3:]             #3番目以降の要素 #[3 4 5]
print arr[1:4]            #1番目から3番目の要素 #[1 2 3]
arr[1:4] = 0,-1,100       #1番目から3番目の要素変更
print arr                 #[  0   0  -1 100   4   5]
print (where(arr>0,arr,3))#0より大きいものは3  #[  3   3   3 100   4   5]
print sort(arr)           #ソート #[ -1   0   0   4   5 100] 

NumPyの2次元配列

from numpy import *

#2次元配列の作成(型の指定つき)
a = array([[12,11,10,9],
           [8,7,6,5],
           [4,3,2,1]],dtype=float)

print a
'''
[[ 12.  11.  10.   9.]
 [  8.   7.   6.   5.]
 [  4.   3.   2.   1.]]
'''
a = a.astype(int32) #後から型を変えることも可能
print a
'''
[[12 11 10  9]
 [ 8  7  6  5]
 [ 4  3  2  1]]
'''
print a.ndim        #次元数
#2
print a.size        #サイズ
#12  
print a.shape       #次元の要素数
#(3L, 4L)
print a.dtype       #要素のデータ型
#int32
print a[0]          #0行目の取得
#[12 11 10  9]
print a[:,0]        #0列目の取得
#[12  8  4]
print a[0][0]       #0行目0列目の取得
#12
print a*a           #掛け算。行列の掛け算ではないので注意
'''
[[144 121 100  81]
 [ 64  49  36  25]
 [ 16   9   4   1]]
'''
print sqrt(a)       #平方根
'''
[[ 3.46410162  3.31662479  3.16227766  3.        ]
 [ 2.82842712  2.64575131  2.44948974  2.23606798]
 [ 2.          1.73205081  1.41421356  1.        ]]
'''
print sort(a)                  #ソート
'''
[[ 9 10 11 12]
 [ 5  6  7  8]
 [ 1  2  3  4]]
'''
print sort(a, axis=0)          #列でソート
'''
[[ 4  3  2  1]
 [ 8  7  6  5]
 [12 11 10  9]]
'''
print sort(sort(a), axis=0)    #行でソートした後に列でソート
'''
[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]
'''
print sort(a, axis=None)       #1次元としてでソート
#[ 1  2  3  4  5  6  7  8  9 10 11 12]

for i,elem in enumerate(a):    #インデックスも取得できる
    print i,elem
'''
0 [12 11 10  9]
1 [8 7 6 5]
2 [4 3 2 1]
'''
print a.sum()   # 合計
#78
print a.max()   # 最大値
#12
print a.min()   # 最大値
#1

reshape

from numpy import *

a = numpy.arange(0, 12, 1)
print a
#[ 0  1  2  3  4  5  6  7  8  9 10 11]

print a.reshape(2, 6)
'''
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]]
'''

print a.reshape(4, 3)
'''
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]
'''

Numpyでベクトル演算

配列を使うだけ。
from numpy import *
v1 = array( [ 1, 2, 3 ] )
v2 = array( [ 0, -1, 2 ] )

print v1 + v2             #足し算 [1 1 5]
print v1 * v2             #要素の掛け算 [0 -2 6]
print dot(v1,v2)          #内積 4
print cross(v1,v2)        #外積 [ 7 -2 -1]
print linalg.norm(v1)     #長さ 3.74165738677
print v1/linalg.norm(v1)  #正規化 [ 0.26726124  0.53452248  0.80178373]

行列はmatrix

リストまたは文字列から作成する
from numpy import *

print(matrix('1 2 3'))               #1×3行列を文字列から作成
#[[1 2 3]]
print(matrix([1,2,3]))               #1×3行列をリストから作成
#[[1 2 3]]
print(matrix('1; 2; 3'))             #3×1行列を文字列から作成
'''
[[1]
 [2]
 [3]]
'''
print(matrix([[1],[2],[3]]))         #3×1行列をリストから作成
'''
[[1]
 [2]
 [3]]
'''
print(matrix('1 2 3; 4 5 6; 7 8 9')) #3×3行列を文字列から作成
'''
[[1 2 3]
 [4 5 6]
 [7 8 9]]
'''
print(matrix([[1,2,3],[4,5,6],[7,8,9]])) #3×3行列をリストから作成
'''
[[1 2 3]
 [4 5 6]
 [7 8 9]]
'''

配列と行列を間違えないこと

似てるけど掛け算すると値は違う
from numpy import *

arr =  array([[ 1,  2,  3],
              [ 4,  5,  6],
              [ 7,  8,  9]])
       
mat = matrix([[ 1,  2,  3],
              [ 4,  5,  6],
              [ 7,  8,  9]])

print arr.shape #各要素数
#(3L, 3L)
print mat.shape #各要素数
#(3L, 3L)

print arr + arr #配列の足し算
'''
[[ 2  4  6]
 [ 8 10 12]
 [14 16 18]]
'''
print mat + mat #行列の足し算
'''
[[ 2  4  6]
 [ 8 10 12]
 [14 16 18]]
'''

print arr * 3   #配列を定数倍
'''
[[ 3  6  9]
 [12 15 18]
 [21 24 27]]
'''
print mat * 3   #行列を定数倍
'''
[[ 3  6  9]
 [12 15 18]
 [21 24 27]]
'''

print arr * arr #配列の掛け算
'''
[[ 1  4  9]
 [16 25 36]
 [49 64 81]]
'''
print mat * mat #行列の掛け算
'''
[[ 30  36  42]
 [ 66  81  96]
 [102 126 150]]
'''

配列でも行列の演算はできた

配列の場合で行列の掛け算を行うにはdot関数を使う。行列演算の他の関数も使用できる。
from numpy import *

arr =  array([[ 1,  2,  3],
              [ 4,  5,  6],
              [ 7,  8,  9]])
       
mat = matrix([[ 1,  2,  3],
              [ 4,  5,  6],
              [ 7,  8,  9]])

print arr.dot(arr) #配列でも行列の掛け算ができる arr * arr はダメ
'''
[[ 30  36  42]
 [ 66  81  96]
 [102 126 150]]
'''
print mat * mat    #行列の掛け算 mat.dot(mat) でも良い
'''
[[ 30  36  42]
 [ 66  81  96]
 [102 126 150]]
''

行列を配列に格納する場合

from numpy import *
#arrayの中に入れるとうまくいかなかったのでリストにする。またはリストにappendで入れていく。
a = [
matrix('1 2 3; 4 5 6; 7 8 9'),
matrix('10 20 30; 40 50 60; 70 80 90'),
matrix('-1 -2 -3; -4 -5 -6; -7 -8 -9')
]
 
for i,elem in enumerate(a):
    print i ,repr(elem)

''' 
0 matrix([[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]])
1 matrix([[10, 20, 30],
        [40, 50, 60],
        [70, 80, 90]])
2 matrix([[-1, -2, -3],
        [-4, -5, -6],
        [-7, -8, -9]])
'''

行列の演算


from numpy import *
 
a = matrix([[ 1,  2,  3],
            [ 4,  5,  6],
            [ 7,  8,  9]])
        
b = matrix([[ 9,  8,  7],
            [ 6,  5,  4],
            [ 3,  2,  1]])
                       
print a * b          #行列積 a.dot(b) でもよい
'''
[[ 30  24  18]
 [ 84  69  54]
 [138 114  90]]
'''
 
print a.I            #逆行列 linalg.inv(a) でもよい
'''
[[ -4.50359963e+15   9.00719925e+15  -4.50359963e+15]
 [  9.00719925e+15  -1.80143985e+16   9.00719925e+15]
 [ -4.50359963e+15   9.00719925e+15  -4.50359963e+15]]
'''
 
print a.T            #転置行列 transpose(a) でもよい
'''
[[1 4 7]
 [2 5 8]
 [3 6 9]]
'''
 
print a.diagonal()   #対角要素をベクトル化 diagonal(a)
#[[1 5 9]]
 
vec = a.diagonal()                #対角要素をベクトル化
c = matrix(zeros((3, 3), int))    #代入用のマトリクス作成
fill_diagonal(c,vec)              #対角要素をマトリクスへ代入
print repr(c)
'''
matrix([[1, 0, 0],
        [0, 5, 0],
        [0, 0, 9]])
'''

v = array([2,4,6])              
print a.dot(v)                    #行列とベクトルの積
#[[ 28  64 100]]

2015年9月8日火曜日

mayaスタディ

maya勉強中。
あとmayaのスクリプトも使えるようになりたいのでそれも勉強中。

softimageユーザがmayaに移行するにあたってのチュートリアルで20本の動画でまとめられている。
Softimage to Maya Bridge

Mayaの基本的な説明。日本語で19本でまとめられている
Maya Learning Channel

mayaメモ

  • ディペンデンシーグラフについて
    • MayaもSI同様ノードのネットワークを構築するが、SIのオブジェクト指向とは違いそれぞれのオブジェクトは一連のノードの集まりでできている。
    • ノードの繋がりはハイパーグラフで見ることができる
    • ハイパーグラフはsiのスケマティックビューと似ているがオブジェクト間の接続は見えない
    • ノードエディタの見た目はSIのレンダーツリーやICEに近い
    • アトリビュートエディタで接続されているノードの編集ができる。
    • チャンネルボックスではそのノードの入力と出力を確認できる
    • オブジェクトに対し行われるオペレーションはコンストラクションヒストリと呼ばれる。SIのコンストラクションヒストリと同じ。
  • シーン設定関連
    • Mayaのグリッド単位はセンチやメートルで指定できる。デフォはcm。角度はDegree
    • フレームレートも設定可能。デフォは24fps
    • 上軸がYかZを指定できる。デフォはSIと同じY
  • 表示モード
    • 4:ワイヤーフレーム
    • 5:シェーディング表示モード
    • 6:テクスチャ表示
    • 7:シーン中のライト有効
  • カメラ操作Mayaでは[Alt] 
    • 左ボタン : オービット
    • 中ボタン : トラック
    • 右ボタン : ドリー
  • メニュー切り替え
    • F2 : モデリング
    • F3 : リギング
    • F4 : アニメーション
    • F5 : fx
    • F6 : レンダリング
  • 表示非表示H : オブジェクト選択時
  • Q 選択ツール
  • 8 オブジェクトモードとコンポネントモードの切り替え
  • ポネント選択モード
    • F9 : 頂点
    • F10 : エッジ
    • F11 : ポリゴン
  • オブジェクト選択モードまたはコンポネント選択時の追加選択等
    • 追加選択 shift + ctrl
    • 追加選択(トグル) shift
    • 除外 ctrl
    • 反転shift + ctrl + I
  • コンポネント選択時の選択操作
    • コンポネント範囲拡大と縮小 :  Shift [>]、Shift [<]
    • 次のコンポネント選択するときに Shit ダブルクリックで その方向を一括選択する
    • 次のコンポネント選択するときに間をあけ多場所で Shiftダブルクリックで間を選択できる
    • 背面を選択しない選択はTabを押しながら選択
    • レイキャスト選択で背面を選択しない場合は選択ツールのアイコンをダブクリで[カメラベースの選択範囲]を有効にする
    • 選択以外を非表示 Shift I
    • 選択状態でCtrl右クリックで別のコンポネントを選択できる。(頂点からエッジ等)
    • コンポネント選択以外を非表示 Shift I
  • オブジェクト操作
    • W : 移動
    • E : 回転
    • R : スケール
    • Shift 中クリックを使えばマニピュレータを掴まなくても軸方向に動かすことが可能
    • マニピュレータのサイズは+,-で変更可能
    • Ctrl T でユニバーサルマニピュレータ
    • ワールド、ペアレント、ローカル軸の指定やステップの指定、親だけ個別に動かすことも可能
    • ピボット編集はinsertでもできる
  • テキストボックスに算術オペレーションを使う場合は 
    • +=n : 現在の値に加算
    • *=n : 現在の値に乗算
    • /=n : 源氏の値に除算
    • +=n% : 現在の値に%で加算
  • モデリングツールキットを使えばモデリングがSi風にできるかも。右上の金槌のアイコン
  • 最後のアクションを続けて実行する場合はG
  • スープラモードがなくスティッキーモードのみ
  • Ctrl スペースで フルスクリーン表示のトグル
  • 右クリックでコンポネントメニュー。Shift右クリックでコンポネント用のメニューが表示
  • SIのプロパティページのロックと同じようにするにはアトリビュートエディタの中のリスト>[選択したアトリビュートの自動ロード]をオフにすればよい
  • アトリビュートスプレッドシート。window>GeneralEditorの中。MayaのアトリビュートエディタではSIのように複数のメッシュをプロパティページで一括編集ができないのでこれを使う
  • プレイブラストとは : SIで言うフリップブックのこと
  • SIのメモカムと似た機能 : ビュー>ブックマーク を使う。カメラのアトリビュートとして保持される
  • ロケータを選択するとその下のメッシュもハイライト表示されているが選択されているわけではないので注意。mayaのグループはSIのグループとは違い、SIのトランスフォームグループと似ている。Ctrl + G でグループ作成
  • 選択セットはポリゴンや頂点を登録できる。SIのクラスタと似ている。
  • ニュートラルポーズがないので必要ならポーズのプリセットを利用する
  • 親の設定 : 複数選択してP。最後に選択されたものの子供になる
  • SIのモデルのように扱うにはアセットというものを使う。このアセットはリファレンスすることもできる
  • マテリアル割り当てるときは、ハイパーシェードからドラッグ。またはメッシュ選択し、ハイパーシェードから右クリックで割り当てる
  • マテリアルからオブジェクト選択。ハイパーシェードでマテリアル選択して右クリック
  • プリファレンスの設定は一番右下あたりにあるアイコン(非常口みたい)から行ける
2015年9月7日月曜日

Maya色管理3 数値入力

入力カラー値の変換テスト

どうやら数値入力は色空間の指定はレンダリング空間で行うことになっている。
そのためレンダリング空間を後から変えると設定した色が物理的には違った色になってしまう。
なのでレンダリング空間を後から変えた場合はカラーの値を修正しなくてはいけない。
入力カラー値に対しての色空間指定はできないことが問題。(テクスチャではできる)

一応ディスプレイ空間での数値の参照と入力は可能だが、レンダリング空間に紐づいているため注意が必要。

例えばレンダリング空間がACEScgで表示空間がsRGBだった場合はカラー値の入力としてはXYZを使うことはできない。
この場合はレンダリング空間のACEScgの値を直接入力するか表示空間のsRGBで入力するしかない。

試しにDisplay Spaceで値を入れる

レンダリングスペースscene-Linear CIX XYZ
ビュー変換
sRGB gamma

左はビュースペース(sRGB) R=G=B= 1.0  右はR=G=B= 0.3 としてレンダリングスペースに切り替えた時の値を確認。



表示空間レンダリング空間
R1095
G11
B11.089


表示空間レンダリング空間
R0.30.070
G0.30.073
B0.30.080


表示空間sRGB(D65)の値をレンダ空間XYZに変換された値になっていることがわかる。
sRGB値 ←→ リニアsRGB ←→ CIE XYZ
このXYZはリニア値であり、この値がレンダリング空間で使われる値となる

検算する場合はここを使うとよい
http://www.brucelindbloom.com/ColorCalculator.html (Lindbloomのサイト)





表示空間で値を見たり入力することはできるが、レンダ空間を切り替えた場合は表示空間での値が変更される。(カラー値がレンダリング空間に紐づいているため)
ここがテクスチャの場合とおおきく違う。
正しい値を入れていた場合に、後からレンダ空間を切り替えたら、そのレンダ空間で正しくなるように値を変換しなおさなくてはいけない

Display Spaceの外側の色は?

DisplaySpaceでは表せない高彩度の値はどうなの?

RGBにマイナスを許せば大丈夫?
通常RGBにマイナスを入れるとレンダリング計算に破たんが起きるが、DisplaySpaceでマイナスなだけで、レンダリング空間ではマイナスになっていないので問題ないと思われたが....



バグがありそう

sRGBの色域外のxy座標(0.1,0.7)を例にする。
明度Y=0.5とした場合。xyY(0.1,0.7,0.5) は XYZに変換するとXYZ(0.0714,0.5,0.1429) となり、sRGB(-0.803,0.943,0.255)となる。8bitで表すと(-205,240,65)となるはず



Rチャンネルの値が大きく違う。
他にも調べたがマイナスになるチャンネルがすべて変な値になっていることがわかった。
現状では表示色空間で色域外を指定すると正しいレンダリング空間に変換してくれない。
表示領域外の値はレンダリング空間で値を直接指定するしか方法はない。
2015年9月6日日曜日

Maya色管理2 レンダ空間と白色

引き続きMaya2016のカラー管理調査。

2015/9/15内容修正

ホワイトバランスは?

レンダリングスペースやディスプレイスペースでの白色点は何かを調べたい。
ちなみに白色点の変更はカラー管理ではできないみたい。

白が何色になるかの実験

新規シーンでプレーンを作成し、ランバートの拡散を1.0にしてカラーは0.5に、1.0の並行光源を真上から当てる。
その後レンダリング空間を切り替える。表示空間はsRGBとする。

レンダリング空間をCIE XYZにしたら色が変わった

デフォルトの[scene-linear Rec 709/sRGB]では示される値はRGB=188だったものが R:204, G:183, B:180になり、少し赤みが帯びた。

今回のケースでは表示空間に変換すると色が変わるということでレンダ空間と表示空間の白色点が違うということ。
少なくとも[scene-linear Rec 709/sRGB]と[scene-linear CIE XYZ]では違うということになる。

下の画像の見た目では少し赤みが帯びているが、左のRGB値のMayaのスポイト機能で測った値は赤くないことからもレンダ空間と表示空間の白色点の違いによることだと推測できる。
右の値が表示空間の補正後の値となる。


ビューポートのビュー変換を一時的に無効にするとレンダ空間の値そのものの色が確認できる。
方法はビュー変換を[Row]にする。

その他のレンダリング空間でもテスト 15/10/02 修正

色はレンダ空間で[0.1, 0.2, 0.4]を指定した場合に、sRGB空間のプレビューで確認した時の色は?

予想1.レンダ空間から表示空間に変換される値。白色点変更(ホワイトバランス)を考えない場合

sRGBXYZACEScgSharp RGB
to sRGG8903926
to sRGB124148126122
to sRGB170167169169

予想2.レンダ空間から表示空間に変換される値。(変換時に白色点変更D65(Bradford)を行った場合)

sRGB(D65)XYZ(E)ACEScg(D60)Sharp RGB(E)
 to sRGB(D65)890300
 to sRGB(D65)124151127125
 to sRGB(D65)170174176176

結果

sRGBXYZACEScgSharp RGB
to sRGB890300
to sRGB124148127125
to sRGB170167176176

表示時に、レンダリング空間から表示空間の白色点へ変更していることがわかった。
また、XYZ空間の白色点はD65として扱われている。
RGBすべて1.0とした場合はどの色空間でレンダリングしても白になる。

ホワイトバランス考慮した時の演算の覚書(ACEScg. D60 to D65)


変換マトリクスと白色点