2016年09月16日

modo10のスクリプトについて調べてみた その15

前回に引き続き「QPushButton」を調べてみたい。

「QPushButton」には下の画像のようにメニューを追加できる。

fig01

これには「QPushButton.setMenu()」を使って「QMenu」オブジェクトを追加すればいい。いろいろ試してみたらメニューから先は「self」をつけてインスタンス変数にしないとダメなようだ。

import lx
import lxifc
import PySide
from PySide.QtGui import *

class MenuTest(lxifc.CustomView):

    def customview_Init(self, pane):
        if pane is None:
            return False
        custPane = lx.object.CustomPane(pane)
        if not custPane.test():
            return False
        parent = custPane.GetParent()
        widget = lx.getQWidget(parent)
        if widget is not None:
            layout = QVBoxLayout()
            btn = QPushButton("Button")
            self.mnu  = QMenu()
            act1 = self.mnu.addAction("action1")
            act2 = self.mnu.addAction("action2")
            self.mnu.addSeparator()
            self.submnu  = QMenu("Sub Menu")
            act3 = self.submnu.addAction("action3")
            act4 = self.submnu.addAction("action4")
            self.mnu.addMenu(self.submnu)
            act1.triggered.connect(self.on_act1)
            act2.triggered.connect(self.on_act2)
            act3.triggered.connect(self.on_act3)
            act4.triggered.connect(self.on_act4)
            btn.setMenu(self.mnu)
            layout.addWidget(btn)
            widget.setLayout(layout)
            return True
        return False
		
    def on_act1(self):
        print "action 1"

    def on_act2(self):
        print "action 2"

    def on_act3(self):
        print "action 3"

    def on_act4(self):
        print "action 4"

lx.bless(MenuTest, "My Menu Test")

これが実行結果。

fig02

メニューはネスティング出来て、「addSeparator()」によって「action2」と「Sub Menu」の間に横線が入っているのがわかる。また、addAction()の戻り値が「PySide.QtGui.QAction」オブジェクトで、これをクリックするシグナルは「PySide.QtGui.QAction.triggered()」で、これにスロットをコネクトすれば、選択した時にスロットが起動されるようになる。

続きはまた次回。

次回の定期更新は9月26日になります。

modo10ブログ目次



take_z_ultima at 11:30|この記事のURLComments(0)TrackBack(0)modo | CG

2016年09月15日

3ds Max 2017の新機能を調べてみた その27 3dsmax 2017

マップアイテムに「カラーマップ」というアイテムが追加された。

fig01

このアイテムは単色、またはさらに他のマッピングアイテムの出力をガンマ、ゲインで調整して出力するマッピングアイテムだ。

「逆ガンマ」をONにすると、逆ガンマ補正がかかり、ゲインで除算される。

これを通して単色や画像を扱えば、このアイテムをインスタンス化出来るので、同じ色や画像を一括して扱えるようになる。

例えばマテリアルの複数のパラメータに同じ色を適用していてそれが変更になった時に色のかわりにこのマップのインスタンスを使っていれば、一括して色の変更が出来る。

それではまた次回。

maxまとめページ



take_z_ultima at 11:30|この記事のURLComments(0)TrackBack(0)3ds Max | CG

2016年09月14日

modo10のスクリプトについて調べてみた その14

前回に引き続き「QPushButton」ウィジェットについて調べてみたい。

Pysideのウィジェットはスタイルシートを使ってアレンジする事ができる。そのためのメソッドが

PySide.QtGui.QWidget.setStyleSheet(styleSheet)

だ。

スタイルシートの書式は、

セレクタ{プロパティ:値; ・・・ ; プロパティ:値;}

という形で「セレクタ」を設定する。例えば「QPushButton」の背景の色を赤いにしたければ、セレクタは「QPushButton」で、背景のプロパティ名は「background-color」で、赤色は「red」または「#ff0000」なので、

QPushButton{background-color:red;}

となる。これを前回のコードに入れてみた。

import lx
import lxifc
import PySide
from PySide.QtGui import *

class BStyleTest(lxifc.CustomView):

    def customview_Init(self, pane):
        if pane is None:
            return False
        custPane = lx.object.CustomPane(pane)
        if not custPane.test():
            return False
        parent = custPane.GetParent()
        widget = lx.getQWidget(parent)
        if widget is not None:
            layout = QVBoxLayout()
            btn = QPushButton("Button")
            f=btn.font()
            f.setPointSize(30)
            btn.setFont(f)
            btn.setStyleSheet('QPushButton{background-color: red;}')
            layout.addWidget(btn)
            widget.setLayout(layout)
            return True
        return False

lx.bless(BStyleTest, "Button Style Test")

これが実行結果。背景が赤になった。

fig01

他にも以下のプロパティが使えるようだ。値の表現や単位はCSSに則っている。

プロパティ名 用途
color 文字の色 white
background-color 背景の色 red
border-style 境界のスタイル outset
border-width 境界の幅 2px
border-radius 角の丸み 10px
border-color 境界の色 #0000ff
font フォントスタイル bold 14px
max-width 最大幅 20em
min-width 最小幅 10em
padding 余白 6px

PySideで使えるセレクタは、以下の書式。[ ]で囲まれている部分は省略できる。

クラス名[#オブジェクト名][:アクション名]

「オブジェクト名」は「PySide.QtCore.QObject.setObjectName(name)」で名前を付ける事で作用するウィジェットを絞る事が出来る。

「アクション名」は「hover」「pressed」などで、カーソルがボタンの上に入った時やボタンが押された時の状態だ。これらを組み合わせてみたのが以下のコードだ。

import lx
import lxifc
import PySide
from PySide.QtGui import *

class BStyleTest(lxifc.CustomView):

    def customview_Init(self, pane):
        if pane is None:
            return False
        custPane = lx.object.CustomPane(pane)
        if not custPane.test():
            return False
        parent = custPane.GetParent()
        widget = lx.getQWidget(parent)
        if widget is not None:
            layout = QVBoxLayout()
            btn = QPushButton("Button")
            btn.setStyleSheet(\
             'QPushButton{'\
              + 'color: yellow;'\
              + 'background-color: red;'\
              + 'border-style: outset;'\
              + 'border-width: 2px;'\
              + 'border-radius: 10px;'\
              + 'border-color: blue;'\
              + 'font: bold 14px;'\
              + 'max-width: 20em;'\
              + 'min-width: 10em;'\
              + 'padding: 6px;'\
            + '}'\
            + 'QPushButton:hover{'\
              + 'border-width: 4px;'\
              + 'border-color: green;'\
            + '}'\
            + 'QPushButton:pressed{'\
              + 'color: white;'\
              + 'background-color: blue;'\
            + '}')
            layout.addWidget(btn)
            widget.setLayout(layout)
            return True
        return False

lx.bless(BStyleTest, "Button Style Test")

「max-width」と「min-width」を設定してあるので、パレットの幅を変えても「max-width」よりボタンは小さくならないし、「min-width」より大きくならないようになった。

fig02

そしてボタンの上にカーソルをのせると縁が太くなって色が緑に変り、ボタンを押すと文字の色が白に、背景が青に変るようになった。

fig02

続きはまた次回。

modo10ブログ目次



take_z_ultima at 11:30|この記事のURLComments(0)TrackBack(0)modo | CG

2016年09月13日

3ds Max 2017の新機能を調べてみた その26 3dsmax 2017

前回に引き続き「スキン」モディファイヤだ。

「ボクセル」ソルバはメッシュをボクセルと呼ばれる多面体に空間分割し、そのボクセルとスケルトンの距離からウェイト値を計算する方式らしい。メッシュをボクセル化する事でメッシュが大雑把にどういう形状をしているか(どう曲がってどう分岐してるかとか)をコンピュータが把握してウェイトマップを施すので、単なるスケルトンからの距離でウェイトマップを施すのと違って精度の高いマッピングをする事が可能になるらしい。

このソルバも「スキン」モディファイヤの「ウェイとプロパティ」グループの「ウェイトソルバ」を「ボクセル」にして、隣の「…」ボタンを押して、

fig01

「測地線ボクセルソルバ」を出して「適用」ボタンを押すことで適用する。

fig02

このソルバを使う大前提はボーンがメッシュの中に入っている事だ。ボーンがメッシュの中に入っていることでそのメッシュが包む空間をボクセル化してウェイトマップを生成するためのようだ。

前回「ヒートマップ」で試したシーンで「ボクセル」ソルバを試してみると、ボーンがメッシュに入るまでメッシュのウェイト値が全て0のままだった。

fig03

そんなわけでメッシュが平面だと「ボクセル」ソルバは使えない。

fig04

ボックスで試してみたらポリゴンの一部分が欠けて穴があいている状態でも機能した。

fig05

そこでどこまで大丈夫か試してみた。下の画像が限界点だ。

fig06

もう一枚削除すると1つのボーンにしか反応しなくなった。

fig07

さらに削除して平面になると全く反応が無くなった。

fig08

平面が平らではない場合はボクセルで区切る空間がうまれるので反応する。

fig27

今度はこんな形のメッシュで試してみた。

fig09

まずは「エンベローブ」で。

fig10

「エンベローブ」で「すべての頂点にウエイトを設定」をONにするとこんな感じ。

fig11

「ヒートマップ」でこのようなパラメータでやってみると、

fig13

こんな感じになった。「エンベローブ」ではボーンに垂直な方向では同じ値になったけど、「ヒートマップ」の場合は「フォールオフ」の影響で遠くなるとブレンド割合が高くなっている。

fig12

「フォールオフ」を1にすると離れているところのウエイトマップもコントラストがはっきりしてっくる。

fig16

さらに「最大影響数」を1にするとどっちかのボーンの影響のみになるのでエンベローブに近くなった。ただしエンベローブの場合はボーンの継ぎ目部分はブレンドマップになっているけどこっちはブレンドされない。

fig17

ボーンを変形させてみるとその差がよくわかる。これが「エンベローブ」の場合。

fig18

そしてこれが「ヒートマップ」で「最大影響数」を1にした場合。

fig19

これはデフォルト状態の「ヒートマップ」の場合。

fig20

そしていよいよ「ボクセル」ソルバを使ってみた。

fig14

これがその結果。顕著な違いは下の部分。メッシュとしての構造で見ると棒状のものが折れ曲がっているから、下の部分は左側のボーンが近いと判断したわけだ。

fig15

このように「ボクセル」ソルバはメッシュ構造を認識したウェイとマッピングをしてくれる。

例えば下のように分岐しているメッシュにボーンを入れてバインディングすれば、

fig21

この分岐部分が隣接していても相互に影響を与える事無くこのように綺麗にバインディングできる。

fig22

しかしボクセル分割には限度があって、「最大解像度」パラメータで1024までしか設定できない。だからメッシュ全体に対して細かい部分はボクセルのサイズが充分に取れないために今のところ期待通りには行かないようだ(たぶん・・・)。だからキャラクターを1つのメッシュとすると、腕や脚のウェイトマップはうまく行くけど指は細かすぎて無理みたいな事になるようだ。例えば上記の例でもこのように大きな構造の一部分になれば、

fig23

このようにバインディングが曖昧になってしまう。

fig24

矢印のポイントのウェイト値を見ると、ブレンディングされているのがわかる。

fig25

ここで「最大解像度」を256から1024まであげて計算しなおしてみると、再びバインディング精度をあげることができた。

fig26

「回転数を使用(Use Winding Number)」オプションはマニュアルには「精度は高くなりますが、計算が遅くなります」としか書いていない。だから想像でしか言え無いんだけど、「winding number」と言うと、ある点が多角形の内側にあるか外側にあるかを判定するアルゴリズムが思い当たる。もしそれだとすると、「回転数を使用」はボクセルの内外判定とかなのかな?いろいろ試すと確かにこのオプションによって変化は見られたが、それがどんな影響なのかについて明確なものは得られなかった。

追加された2つのソルバはいずれもウェイトマップのベイクをするので「エンベローブ」とは併用しにくい。そこでエンベローブのかわりに「ボクセルスキニング」と併用するための「エンベローブ」の代用が「ヒートマップ」なのかな。

それではまた次回。

maxまとめページ



take_z_ultima at 11:30|この記事のURLComments(0)TrackBack(0)3ds Max | CG

2016年09月12日

modo10のスクリプトについて調べてみた その13

今回はPysideで使えるウィジェットをいくつか調べてみたい。

まずは「QPushButton」だ。これについては何度も出て来て見飽きた感もあるけど、マニュアルを見るといろいろと機能が付いている。

「QPushButton」のコンストラクタは以下の通り。

class PySide.QtGui.QPushButton([parent=None])
class PySide.QtGui.QPushButton(icon, text[, parent=None])
class PySide.QtGui.QPushButton(text[, parent=None])

Parameters: icon – PySide.QtGui.QIcon parent – PySide.QtGui.QWidget text – unicode

「parent」はボタンがどのウィジェットに乗るかを指定する。前回やったレイアウトを使わないで直接パレットにボタンを配置する時に使ったね。レイアウトを使う場合は割り当てをレイアウトがやるので放置だ。そして「text」でボタンの上に書かれる文字列を設定する。この時文字列の中に「&」を入れると、「&」の次に来る文字がこのボタンのショートカットになり、「ALT」ボタンと共に押すとこのボタンがクリックされる。例えばこんな感じ。

import lx
import lxifc
import PySide
from PySide.QtGui import *

class MyButtonTest(lxifc.CustomView):

    def customview_Init(self, pane):
        if pane is None:
            return False
        custPane = lx.object.CustomPane(pane)
        if not custPane.test():
            return False
        parent = custPane.GetParent()
        widget = lx.getQWidget(parent)
        if widget is not None:
            layout = QVBoxLayout()
            btn = QPushButton("&Button")
            layout.addWidget(btn)
            widget.setLayout(layout)
            return True
        return False

lx.bless(MyButtonTest, "QPushButton Test")

これを実行して「カスタムビュー」で「QPushButton Test」を呼び出すと下のようになり、「ALT+B」キーでボタンをクリックできる。ボタンの文字をよく見ると先頭の「B」の文字にアンダーバーがついているのがわかる。

fig01

このようにボタンのテキストで「&」は特殊文字になるのでボタンの文字列の中で「&」の文字を使いたい時は「&&」と2つ並べて書くと「&」1つの文字として表示される。例えば「A&B」と表示したければ、「A&&B」とすればいい。

「icon」はボタンの文字の前にアイコンを設定するためのパラメータだ。これは「PySide.QtGui.QIcon」型のオブジェクトとして渡す必要がある。これもコンストラクタはいろいろあるようだけど、画像ファイルを渡す方法が簡単そうだ。下のプログラムは「my_icon.jpg」という画像ファイルを作って、このスクリプトと同じディレクトリに置いて読み込ませた例。スクリプトファイルがある場所は「__file__」で調べられるので、「os.path.dirname()」を使ってそこからディレクトリ名のフルパスを得て、それを「my_icon.jpg」に合成して画像ファイルのフルパス名を作って「QIcon」のコンストラクタに渡してアイコンを作っている。後はボタンに渡せばボタンにアイコンが追加される。また、アイコンの足図は「setIconSize()」で変更できて、引数として「QSize」型のオブジェクトが必要なので、これをコンストラクタ「QSize(w,h)」で生成している。

import lx
import lxifc
import PySide
from PySide.QtGui import *
import os

class MyButtonTest(lxifc.CustomView):

    def customview_Init(self, pane):
        if pane is None:
            return False
        custPane = lx.object.CustomPane(pane)
        if not custPane.test():
            return False
        parent = custPane.GetParent()
        widget = lx.getQWidget(parent)
        if widget is not None:
            layout = QVBoxLayout()
            icon = QIcon('%s\my_icon.jpg' % os.path.dirname(__file__))
            btn = QPushButton(icon,"Button")
            f=btn.font()
            f.setPointSize(30)
            btn.setFont(f)
            btn.setIconSize(PySide.QtCore.QSize(30,30))
            layout.addWidget(btn)
            widget.setLayout(layout)
            return True
        return False

lx.bless(MyButtonTest, "Button Icon Test")

これが実行結果。

fig02

続きはまた次回。

modo10ブログ目次



take_z_ultima at 11:30|この記事のURLComments(0)TrackBack(0)modo | CG
Archives