2016年08月26日

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

前回は「QBoxLayout」とそこから派生した「QHBoxLayout」「QVBoxLayout」を使ってみたけど、その他にもレイアウトはいろいろあるようだ。レイアウトは「QLayout」クラスから派生しているようで、マニュアルでその派生先を見ると以下の種類が見つかった。

レイアウト 特 徴
QBoxLayout 縦または横に配置
QFormLayout 入力フォーム用にラベル付きでウィジェットを配置出来る
QGridLayout 表計算ソフトのように格子を使って配置出来る
QStackedLayout ページ切り替えが出来る

QFormLayout

下のコードは「QFormLayout」に「QLineEdit」と「QComboBox」を配置してみたものだ。見てわかる通りウィジェットを追加する「addRow()」メソッドはウィジェットと一緒にラベルも引数にとっている。

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

class MyLayoutTest(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:
            layoutFrm = QFormLayout()
            lineedit1 = QLineEdit("")
            combobox1 = QComboBox()
            combobox1.addItem("item1")
            combobox1.addItem("item2")
            combobox1.addItem("item3")
            layoutFrm.addRow("name:",lineedit1)
            layoutFrm.addRow("item:",combobox1)
            widget.setLayout(layoutFrm)
            return True
        return False

lx.bless(MyLayoutTest, "My Layout Test")

これがその実行したもの。追加したウィジェットの横に入力したラベルが表示されている。

fig01

QGridLayout

下のコードは「QGridLayout」を使ってボタン4つとライン入力1つを配置してみたものだ。

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

class MyLayoutTest(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 = QGridLayout()
            btn1 = QPushButton("Button1")
            btn2 = QPushButton("Button2")
            btn3 = QPushButton("Button3")
            btn4 = QPushButton("Button4")
            edit1 = QLineEdit("")
            layout.addWidget(btn1,0,0)
            layout.addWidget(btn2,0,1)
            layout.addWidget(btn3,1,0,1,2)
            layout.addWidget(btn4,2,0)
            layout.addWidget(edit1,2,1)
            widget.setLayout(layout)
            return True
        return False

lx.bless(MyLayoutTest, "My Layout Test")
ウィジェットを追加する「addWidget()」メソッドの引数が3つのものと5つのものがあるけど、定義は以下のようになっていて、ウィジェットを配置する矩形領域を表計算ソフトのセルのようなイメージで扱って、左上から縦にrow番目、横にcolumn番目のセルから縦にrowSpan個、横にcolumnSpan個連結したセルにarg__1のウィジェットを配置するような指定方法で、引数が3つのものはその簡略版で、1つのセルに配置するものだ。
  • def addWidget (arg__1, row, column, rowSpan, columnSpan[, alignment=0])
  • def addWidget (arg__1, row, column[, alignment=0])

これが実行結果。1列目はウィジェットの幅にあわせてレイアウトされているけど2列目はレイアウトされるビューポートにあわせてウィジェットの方がストレッチされている。これはラインエディットがストレッチされやすいウィジェットだったために他のウィジェットに影響が出たようだ。ラインエディットが無ければボタンはビューポートの幅にあわせて均等にストレッチされるようだ。

fig02

QStackedLayout

下のコードは「QStackedLayout」を使ってボタン2つとライン入力1つを切り替えるようにしてみたものだ。

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

class MyLayoutTest(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 = QStackedLayout()
            btn1 = QPushButton("Button1")
            btn2 = QPushButton("Button2")
            edit1 = QLineEdit("")
            layout.addWidget(btn1)
            layout.addWidget(btn2)
            layout.addWidget(edit1)
            layoutV = QVBoxLayout()
            combo = QComboBox()
            combo.addItem('Page A')
            combo.addItem('Page B')
            combo.addItem('Page C')
            combo.currentIndexChanged.connect(layout.setCurrentIndex)
            layoutV.addWidget(combo)
            layoutV.addLayout(layout)
            widget.setLayout(layoutV)
            return True
        return False

lx.bless(MyLayoutTest, "My Layout Test")

「QStackedLayout」では「addWidget()」で追加したウィジェットが1つのページとなり、「setCurrentIndex()」メソッドで表示するページを切り替える事が出来る。下のGIFアニメが実行結果だ。

fig03

続きはまた来週。

modo10ブログ目次



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

2016年08月25日

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

前回に引き続き「ベベルプロファイル」モディファイヤだ。

ベベルプロファイルのプリセットとして「(カスタム)」を選ぶか、「べべルプロファイルエディタ」ボタンをクリックすると、

fig01

下の画像のような「ベベルプロファイルエディタ」が表示され、プロファイル形状を作成したり編集したする事ができる。

fig02

起動時の「ベベルプロファイルエディタ」は現在設定されている形状が読み込まれる。プロファイルを作成する開始地点として登録済みプロファイルを使いたい場合はエディタ下にあるプロファイルのプルダウンから選択することで読み込む事が出来る。

fig03

エディタではプロファイルの線をクリックすれば頂点が追加され、ドラッグすれば移動する。「自動更新」ボタンがONの時はエディタ上でのプロファイルの操作がただちにモデルに反映される。

fig05

fig04

追加したポイントは「選択した頂点を削除」ツールで削除でき、

fig06

「カーブをリセット」で「線形」プロファイルに戻す事が出来る。

fig07

「ミラーカーブ」「曲線を反転」ルーツはクリックするたびに対角線でカーブを反転する。

fig08

fig09

fig10

「コーナー」「ベジェコーナー」「ベジェスムーズ」ツールは選択ポイントを切り替える。

fig11

fig12

選択頂点は数値を入力して正確な位置に設定する事が出来る。複数の頂点を選択して、同じ高さを入力することで高さを揃えたりするような使い方も出来る。

fig13

表示範囲や位置はおなじみのツールで移動、フィット、ズーム、範囲ズームなどが出来る。

fig14

作成したプロファイルは「カスタム」というプロファイルになるけどこれは一時的なもので他のプロファイルに切り替えると消えてしまう。残して他でも使いたい場合は「名前を付けて保存」でpリセットとして保存することが出来る。

fig15

プリセットは「マイドキュメント/3dsMax/BevelPresets」フォルダ内に拡張子「bevelpreset」で作成される。プリセットを削除する場合はこのファイルを削除して3dsmaxを再起動すればいいようだ。

それではまた次回。

maxまとめページ



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

2016年08月24日

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

前回見たコードに出てきた「QVBoxLayout」はボタンやラベルなどのウィジェットを自動的に縦に並べる仕組みで、これの横バージョンである「QHBoxLayout」、それらの継承元クラスの「QBoxLayout」レイアウトでは設定によってウィジェットを縦に並べたり横に並べたり出来る。

例えば下のコードはボタンを4つ作って縦にレイアウトに追加するものだ。

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

class MyLayoutTest(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()
            btn1 = QPushButton("Button1")
            btn2 = QPushButton("Button2")
            btn3 = QPushButton("Button3")
            btn4 = QPushButton("Button4")
            layout.addWidget(btn1)
            layout.addWidget(btn2)
            layout.addWidget(btn3)
            layout.addWidget(btn4)
            widget.setLayout(layout)
            return True
        return False

lx.bless(MyLayoutTest, "My Layout Test")

これが実行結果。デフォルト状態ではレイアウトに追加されたウィジェット順に上から下に縦にウィジェットが並ぶようになる。

fig01

上のコードで「QVBoxLayout」を「QHBoxLayout」に変更するとボタンは横に並ぶようになる(同じ名前のカスタムビューは登録出来ないのでコードを変更して試すには違う名前(例えば"My Layout Test2"など)で「bless」するか、modoを立ち上げなおして実行する必要がある)。

fig02

この並ぶ方向は「QBoxLayout」のコンストラクタや「setDirection(Direction direction)」メソッドによって設定することが出来て、セットできる値は以下のようになっている。

Constant Value Description
LeftToRight 0 左から右
RightToLeft 1 右から左
TopToBottom 2 上から下
BottomToTop 3 下から上

パラメータの値は「QBoxLayout.Directions」が持っているので、
「QBoxLayout」を右から左にウィジェットが並ぶレイアウトとして生成したいなら、コンストラクタを

layout=QBoxLayout(QBoxLayout.Directions.RightToLeft)

とすればいい。また、生成したレイアウトの配置方向を変更するなら、

layout.setDirection(QBoxLayout.Directions.RightToLeft)

としてやれば、「QVBoxLayout」でも「QHBoxLayout」でもウィジェトの並びは右から左になる。

また、レイアウトはレイアウトでレイアウトできるw

例えば下のように「QVBoxLayout」2つを「QHBoxLayout」に入れて横にレイアウトする事が可能だ。

fig03

コードは以下のようになって、レイアウトにレイアウトを追加するには「addLayout()」メソッドを使う。

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

class MyLayoutTest(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:
            layoutV1 = QVBoxLayout()
            layoutV2 = QVBoxLayout()
            layoutH1 = QHBoxLayout()
            btn1 = QPushButton("Button1")
            btn2 = QPushButton("Button2")
            btn3 = QPushButton("Button3")
            btn4 = QPushButton("Button4")
            layoutV1.addWidget(btn1)
            layoutV1.addWidget(btn2)
            layoutV2.addWidget(btn3)
            layoutV2.addWidget(btn4)
            layoutH1.addLayout(layoutV1)
            layoutH1.addLayout(layoutV2)
            widget.setLayout(layoutH1)
            return True
        return False

lx.bless(MyLayoutTest, "My Layout Test")

これが実行結果。

fig04

続きはまた次回。

modo10ブログ目次



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

2016年08月23日

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

ベベル時にベベルの稜線にシェイプを与えて変形させる「ベベルプロファイル」モディファイヤでプロファイル用に別に用意していたシェイプオブジェクトが必要なくなった。

fig01

このモディファイヤを使うにはベベルを施したいパスを選択して、モディファイヤリストから「ベベルプロファイル」を選べばいい。

fig02

以前の「ベベルプロファイル」のように他のパスオブジェクトからベベル形状を指定したい場合は、「ベベルプロファイル」グループで「クラシック」を選べばいい。

fig03

「クラシック」を選択すると以前の「ベベルプロファイル」のロールアウトに切り替わり、「プロファイルを選択」ボタンを押して、ベベル形状用のパスを選択して「ベベルプロファイル」を適用できる。

fig04

fig05

「改善済み」を選ぶと新しい方式で「ベベルプロファイル」を適用出来る。

fig06これが新方式の「ベベルプロファイル」のロールアウト。

プリセットで数種類のベベルの形状を持っている。

fig07

fig08

「押し出し」は押し出しの深度を決めるパラメータ。

fig09

「押し出しセグメント」は押し出し部分に生成されるセグメント数

fig10

「ベベルの深度」ベベル部分の深度

fig11

「ベベルの幅」がOFFの場合は「ベベルの深度」にあわせて変化するが、ONにした場合は別々に変更出来るようになる。

fig16

「ベベルプッシュ」ベベルカーブの適用強度を決めるパラメータ。

fig12

「アウトラインのオフセット」ベースになるシェイプのオフセット量

fig13

他のパラメータを0にしてベベルが現れないようにしてみるとこのようにベースになるシェイプがオフセットされているのがわかる。

fig14

「ステップ数」カーブ部分の分割数を決めるパラメータ。多いほどカーブが滑らかになるが、データは増えて操作が重くなる。

fig15

「最適化」はベベルの直線部分のセグメント分割を抑制する。下のGIFアニメは直線部分のあるプロファイルに対して「最適化」をON/OFFして比較してみたものだ。

fig18

「ベベルプロファイルエディタ」を使うとプロファイル形状を作成・修正する事ができる。

fig17

続きはまた次回。

maxまとめページ



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

2016年08月22日

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

ユーザーインターフェースにPythonからQtというGUIツールキットを利用出来るようになって、リッチなインターフェースを組み込む事が出来るようになった。

下の画像はマニュアルにある「My Render Button」という名前のカスタムビューを作ってそこに「Render」ボタンを表示するサンプルを実行した結果だ。このボタンを押すとレンダリングが開始される。

fig01

これを表示するには「レイアウト」メニューから「パレット」→「新規パレット」を選んで新規パレットを生成するなどして表示させるためのビューポートを作成しておいて、ビューポートの左上の「ウィジェット」ボタン(右向き三角形のボタン)を押してウィジェットメニューを出して、「カスタムビュー」から「My Render Button」を選べばいい。

fig02

それではコードの方を見ていこう。どうやら青い文字の部分はカスタムビューにQtのウィジェットを配置する時には必須のようで、テンプレートコードとして保存しておいて使いまわせばいいようだ。

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

def onClicked():
    lx.eval("render")

class MyRenderButton(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()
            renderButton = QPushButton("RENDER!")

            f = renderButton.font()
            f.setPointSize(30)
            renderButton.setFont(f)

            renderButton.clicked.connect(onClicked)

            layout.addWidget(renderButton)
            layout.setContentsMargins(2, 2, 2, 2)
            widget.setLayout(layout)
            return True

        return False

lx.bless(MyRenderButton, "My Render Button")

このテンプレート部分によって検証が済んだ「widget」が得られて、これに対して操作を加えることでGUIが完成する。

上の例ではまず「ウィジェット」を配置するための「QVBoxLayout」を作成し、

layout = PySide.QtGui.QVBoxLayout()

次にボタンを作って、

renderButton = QPushButton("RENDER!")

ボタンの文字フォントサイズを変更して、

f = renderButton.font()
f.setPointSize(30)
renderButton.setFont(f)

ボタンをクリックした時に呼び出すハンドラ(onClicked)をセットして、

renderButton.clicked.connect(onClicked)

このボタンをレイアウトに追加して、マージンを調整し、

layout.addWidget(renderButton)
layout.setContentsMargins(2, 2, 2, 2)

そのレイアウトをテンプレート部分で取得した「widget」にセットする。

widget.setLayout(layout)

ボタンを押した時に呼び出されるハンドラは「render」コマンドを実行するようになっている。

def onClicked():
  lx.eval("render")

ボタンのフォントを調整するのにフォントを呼び出してから変更し、それをまたセットするみたいなQt特有のクセみたいなものがあるけど、それさえわかってくればいろいろ面白いことが出来そうだ。

続きはまた次回。

modo10ブログ目次



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