2021年06月15日

pymxsでUVW座標値を取得してみた その16 3dsmax 2019

前回は「QRubberBand」を書き換えて線分のラバーバンドを作ってみた。今回はこれをさらに改造してフリーラインのラバーバンド?をやってみた。

ダイアログ上をドラッグすると、「stroke」だけカーソルが動くたびにそこまでの線が追加されてカーソルが動いた軌跡が描画される。マウスボタンを離すと線は消える。前回のように単純な直線にしたければ「mouseMoveEvent」のところで新しいポイントをappendしないで「points[-1]」の値を「event.pos()」で更新だけすればいい。「mouseMoveEvent」の太字の部分を消せば直線のラバーバンドになる。

from PySide2.QtWidgets import QDialog,QVBoxLayout,QLabel,QRubberBand
from PySide2.QtCore import QRect,Qt
from PySide2.QtGui import QPainter,QImage,QPen,QBrush,QPixmap
import MaxPlus

class RubberBand(QRubberBand):
	points = []
	def __init__(self,shape,parent=None):
		super(RubberBand, self).__init__(shape,parent)
		
	def paintEvent(self, event):
		if len(self.points) != 0 :
			qp = QPainter(self)
			qp.setPen(Qt.white)
			qp.drawPolyline(self.points)

class PyMaxDialog(QDialog):
	width = 300
	height = 300
	stroke = 3
	def __init__(self, parent=MaxPlus.GetQMaxMainWindow()):
		super(PyMaxDialog, self).__init__(parent)
		self.resize(self.width,self.height)
		self.rubberBand = None
		
	def mousePressEvent(self, event):
		self.origin = event.pos()
		if self.rubberBand == None:
			self.rubberBand = RubberBand(QRubberBand.Rectangle, self)
			self.rubberBand.points = [event.pos()]
			self.rubberBand.points.append(event.pos())
		self.rubberBand.setGeometry(QRect(0,0,self.width,self.height))
		self.rubberBand.show()
		
	def mouseMoveEvent(self, event):
		if (self.rubberBand.points[-2] - event.pos()).manhattanLength() > self.stroke:
			self.rubberBand.points.append(event.pos())
		self.rubberBand.points[-1] = event.pos()
		self.rubberBand.update()
			
	def mouseReleaseEvent(self, event):
		self.rubberBand.hide()
		self.rubberBand.sp = None
		self.rubberBand = None

def main():
	w = PyMaxDialog()
	w.show()

if __name__ == '__main__':
	main()

これが実行結果。

名称未設定 1

続きはまた次回。



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

2021年06月14日

Spherize exampleを調べてみた その7 modo15

Spherize example」の勉強の続きだ。

前回までで「Spherize example」のプログラムを見て来てわかったのは、このプログラムが思ったようには動かないだろうと言う事だ。

下の画像はあるメッシュに対してこのプログラムがどう作用するかを説明するためのものだ。このプログラムではメッシュのバウンディングボックスから取得した「mesh_center(赤い点)」からメッシュの頂点(青い点)までの距離を「point_dist」として、その距離でメッシュを球体化した時の球体の半径「target_dist」を割って「scale」を算出し、これをメッシュの各頂点の座標値「point_pos」にかけて新しい頂点の位置を算出して変形している。

Spherules

「point_pos」に「scale」をかけると言う事は、「point_pos」ベクトルの方向は変えないで長さだけを変更すると言う事だ。つまり図で言えばピンク色の矢印の線上しか頂点は移動しない。

そして各点の原点からの距離と「scale」の間に頂点を球体上に移動させるような相関関係はない。

「scale」は「mesh_center」から各頂点に伸ばしたベクトルを何倍に伸ばしたら「target_dist」になるかを表す数値なんだから、かけ合わせなきゃならないのは「mesh_center」を原点とした各頂点の座標値(ベクトル)、つまり「point_pos - mesh_center」ベクトルだ。

Spherules2

ただ「point_pos - mesh_center」ベクトルに「scale」をかけた位置を新しい頂点位置にすると「mesh_center」が原点に移動してしまうので、生成された位置に「mesh_center」ベクトルを足して補正してやる必要がある。

結果として新しい位置は、

(point_pos - mesh_center) * scale + mesh_center

で求められる事になる。

そこでプログラムの「point_newPos」を算出する式を以下のように修正した。

  point_newPos = (((point_pos[0] - mesh_center[0])*scale + mesh_center[0]),((point_pos[1] - mesh_center[1])*scale + mesh_center[1]),((point_pos[2] - mesh_center[2])*scale + mesh_center[2]))

修正後のプログラムを下のメッシュに適用してみると、

fig 3

このようにその場でメッシュが球体化するようになった。

fig 4

それではまた次回。



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

2021年06月08日

pymxsでUVW座標値を取得してみた その15 3dsmax 2019

前回は「QRubberBand」についてマニュアルのサンプルプログラムを試してみた。

QRubberBand」は選択または境界を示すことができる長方形または垂直・水平線を提供するクラスだ。このクラスの図形を描いているのは「paintEvent()」なので、ここを書き換えちゃえば矩形以外の図形のラバーバンドも出来ちゃうだろうと言う事で試してみたのが下のプログラムだ。

単純に「mousePressEvent()」で線の始点と終点を記憶して、「mouseMoveEvent()」で終点を更新しながら始点から終点まで線を引いてラバーバンドを更新しているだけだ。元の「QRubberBand」はウィジェット全体で半透明な矩形だったので「mouseMoveEvent()」でウィジェットのサイズを変更することでラバーバンドの形状を変えていたけど今回のプログラムでは単純に線を引くだけなので、ダイアログの描画エリアとウィジェットのサイズをそろえてその中に線を引くようにした。そのためウィジェットサイズの変更が無いので表示が更新されないので「update()」メソッドを呼び出して更新している。

from PySide2.QtWidgets import QDialog,QVBoxLayout,QLabel,QRubberBand
from PySide2.QtCore import QRect,Qt
from PySide2.QtGui import QPainter,QImage,QPen,QBrush,QPixmap
import MaxPlus

class RubberBand(QRubberBand):
	sp = None
	ep = None
	def __init__(self,shape,parent=None):
		super(RubberBand, self).__init__(shape,parent)
		
	def paintEvent(self, event):
		if self.sp != None:
			qp = QPainter(self)
			qp.setPen(Qt.white)
			qp.drawLine(self.sp,self.ep)

class PyMaxDialog(QDialog):
	
	def __init__(self, parent=MaxPlus.GetQMaxMainWindow()):
		super(PyMaxDialog, self).__init__(parent)
		width = 300
		height = 300
		self.resize(width,height)
		self.rubberBand = None
		main_layout = QVBoxLayout()
		label = QLabel()
		main_layout.addWidget(label)
		self.setLayout(main_layout)
		
		pdevice = QImage(300,300,QImage.Format_ARGB32)
		pdevice.fill(Qt.black)
		painter = QPainter(pdevice)
		painter.begin(pdevice)
		painter.setPen(Qt.red)
		painter.setBrush(Qt.blue)
		painter.drawRect(50,50,150,100)
		painter.end()
		pixmap = QPixmap.fromImage(pdevice)
		label.setPixmap(pixmap)
		
	def mousePressEvent(self, event):
		self.origin = event.pos()
		if self.rubberBand == None:
			self.rubberBand = RubberBand(QRubberBand.Rectangle, self)
			self.rubberBand.setGeometry(QRect(0,0,300,300))
		self.rubberBand.sp = event.pos()
		self.rubberBand.ep = event.pos()
		self.rubberBand.show()
		
	def mouseMoveEvent(self, event):
		self.rubberBand.ep = event.pos()
		self.rubberBand.update()
			
	def mouseReleaseEvent(self, event):
		self.rubberBand.hide()

def main():
	w = PyMaxDialog()
	w.show()

if __name__ == '__main__':
	main()

これが実行結果。

fig 1

マウスでドラッグすると直線が表示され、ボタンを離すと消える。

続きはまた次回。



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

2021年06月07日

Spherize exampleを調べてみた その6 modo15

Spherize example」の「basic_Execute()」メソッドの勉強の続きだ。

前回はアクティブレイヤーのメッシュオブジェクトをローカライズしてfor文で巡回する構造になっていて、その1つのメッシュのバウンディングボックスの中心点を求めて「mesh_center」に格納するところまで調べた。

今回はその次のforループからだ。ここでは「PointCount()」でメッシュ内の頂点の数を取得して0〜頂点数−1までのiのループを作って全頂点を巡回させている。「range()」はデフォルトで0から始まるから引数の0はいらない気がする。次にメッシュオブジェクトから「PointAccessor()」でローカライズされた「Point」オブジェクトを取得して「point_loc」に格納している。そして「test()」で有効チェックしている。この作業はループの外で1回やればいいね。そして今回も「PointAccessor()」はローカライズされた「Point」オブジェクトを返すので「lx.object.Point()」でローカライズする必要はないはず。

  for i in range(0, mesh_loc.PointCount()):
     point_loc = lx.object.Point(mesh_loc.PointAccessor())
 
     if point_loc.test() == False:
         continue          

次に「Point」オブジェクトから「i」番目の頂点の座標値を取得するために「SelectByIndex()」で座標値を調べたい頂点の番号をセットして、「Pos()」メソッドでその座標値を取得している。

  point_loc.SelectByIndex(i)
  point_pos = point_loc.Pos()

次に距離の公式を使って「mesh_center」と「Point_pos」の距離を算出して「point_dist」に格納する。この距離が0の時はこのあとの処理はスキップする。そしてコマンド引数の「target_dist」をこの距離で割ってその値を「scale」にセットする。

この「scale」を元のポイントの位置「point_pos」にかけて新しいポイントの位置を生成し、「point_newPos」として「SetPos()」メソッドでポイントの新しい位置としてセットする。この作業を全ポイントで繰り返せば各頂点のバウンディングボックスの中心点からの距離に応じて算出される「scale」によって頂点の位置が変更される事になる。

  point_dist = math.sqrt(math.pow((point_pos[0]-mesh_center[0]),2)+math.pow((point_pos[1]-mesh_center[1]),2)+math.pow((point_pos[2]-mesh_center[2]),2))
 
  if point_dist == 0:
      continue
 
  scale = target_dist / point_dist
  point_newPos = ((point_pos[0]*scale),(point_pos[1]*scale),(point_pos[2]*scale))
 
  point_loc.SetPos(point_newPos)         

1つのメッシュレイヤー内の頂点に対して一連の処理が終わったら、n番目のレイヤーのポイントが変更になった事を「SetMeshChange()」でmodoに知らせて、「Apply()」で処理を適用する。これでデータが更新されて表示も更新される。

 layer_scan.SetMeshChange(n, lx.symbol.f_MESHEDIT_POINTS)
 
 layer_scan.Apply()
           

これが1つのメッシュレイヤに対する一連の処理で、それをアクティブレイヤについて巡回しながら行うわけだけど、このプログラムではメッシュがちゃんと丸くならないよね?

例えばこんなメッシュに対してこのコマンドを適用すると、

fig 1

このようになって球体とは程遠い形になる。

fig 2

続きはまた次回。



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

2021年06月01日

pymxsでUVW座標値を取得してみた その14 3dsmax 2019

前回は「QScrollArea」をプログラムに組み込んで表示エリアをスクロールバーでスクロールできるようにしてみた。

今回は「QRubberBand」についてマニュアルのサンプルプログラムを試してみた。

from PySide2.QtWidgets import QDialog,QRubberBand
from PySide2.QtCore import QRect,QSize
import MaxPlus

class PyMaxDialog(QDialog):
	
	def __init__(self, parent=MaxPlus.GetQMaxMainWindow()):
		super(PyMaxDialog, self).__init__(parent)
		width = 300
		height = 300
		self.resize(width,height)
		self.rubberBand = None
		
	def mousePressEvent(self, event):
		self.origin = event.pos()
		if self.rubberBand == None:
			self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
		self.rubberBand.setGeometry(QRect(self.origin, QSize()))
		self.rubberBand.show()

	def mouseMoveEvent(self, event):
		self.rubberBand.setGeometry(QRect(self.origin, event.pos()).normalized())

	def mouseReleaseEvent(self, event):
		self.rubberBand.hide()

def main():
	w = PyMaxDialog()
	w.show()

if __name__ == '__main__':
	main()

これが実行したところ。マウスをドラッグすると始点から矩形が表示され、カーソルの動きにあわせて矩形が伸縮し、ボタンを放すと矩形が消える。もちろん下地に影響は出ないし、下に画像がある場合は矩形の下に半透明で透けて見える。

fig 1

続きはまた次回。



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