- 行列を使った回転計算
- 数値入力による縮小処理
冠歯車をモデリングします。
今までの歯車と違い、歯の向きが冠状になりますので少しモデリングの手順が変わります。
平歯車のモデリング
平歯車側は、半径50mm、歯数18の歯車としました。
「歯車のベース部分をスクリプトで効率化してモデリング」でのスクリプトを使用しました。
この場合、1つの歯の幅は以下のスクリプトで計算できます。
import math
R = 50.0 # 歯車の半径.
gCount = 18 # 歯の数.
angle = 360.0 / gCount # 円上の、1つの歯の角度.
# 円周上の、歯1つ分の長さを計算.
D = (R * math.sin((angle / 2.0) * math.pi / 180.0)) * 2
print D
計算式については「歯車のベース部分をモデリング」の「円周上での1つの歯の長さを計算」の章をご参照くださいませ。
Dは「17.3648177667」となりました。
冠歯車側も、この幅で1つの歯をモデリングすることでかみ合うことになります。
平歯車の「閉じた線形状」を自由曲面パートに入れて、以下のように歯車の形にしました。
冠歯車のモデリング
冠歯車側は平歯車と同じ歯の幅で、歯を上に向けた状態でモデリングする必要があります。
単純に、平歯車と同じ半径50mm/歯数18の冠歯車を作ると2つの歯車はかみ合います。
では、歯数が別の整数値の場合の半径は?
D = (R * math.sin((angle / 2.0) * math.pi / 180.0)) * 2
この式より、Rは以下の式で計算できることになります。
R = D / (2 * math.sin((angle / 2.0) * math.pi / 180.0))
Dは平歯車と同じ「17.3648177667」、angleは「360/歯数」とすると、
歯数が30の場合は以下のようにスクリプトにできます。
import math
D = 17.3648177667 # 歯の幅.
gCount = 30 # 歯の数.
angle = 360.0 / gCount # 円上の、1つの歯の角度.
# 歯の半径を計算.
R = D / (2 * math.sin((angle / 2.0) * math.pi / 180.0))
print R
Rは「83.0626282252」となりました。
さて、ここでは計算された情報より、
歯の幅「17.3648177667」、半径「83.0626282252」、歯数「30」で
冠歯車をモデリングすることにします。
まずは、山形の歯を半径「83.0626282252」の円状に並べる必要があります。
モデリングは手間がかかりますので、Pythonスクリプトで作成します。
冠歯車のベースをスクリプトでモデリング
平歯車をモデリングした際に使用した「開いた線形状」を使用します。
スクリプトで指定した歯の幅で自動でリサイズしますので、この段階では大きさは適当でかまいません。
上面図で6つのポイントからなる「開いた線形状」を用意しました。
「歯車のベース部分をスクリプトで効率化してモデリング」で書いたスクリプトを冠歯車用に修正して使用することにします。
入力値としてDに歯の幅、gCountに歯数(整数値)を入れています。
半径Rは自動計算されます。
import math
# -------------------------.
# X軸中心の回転行列を計算.
# angle 回転角度(度数).
# 戻り値 4x4行列.
# -------------------------.
def get_rotateX(angle):
rad = angle * math.pi / 180.0
cosV = math.cos(rad)
sinV = math.sin(rad)
rotM = [ 1.0, 0.0, 0.0, 0.0,
0.0, cosV, sinV, 0.0,
0.0, -sinV, cosV, 0.0,
0.0, 0.0, 0.0, 1.0 ]
return rotM
D = 17.3648177667 # 歯の幅.
gCount = 30 # 歯数.
angle = 360.0 / gCount # 円上の、1つの歯の角度.
# 歯の半径を計算.
R = D / (2 * math.sin((angle / 2.0) * math.pi / 180.0))
scene = xshade.scene()
# 選択された線形状を複製.
scene.copy()
scene.paste()
# 形状の作成開始.
scene.begin_creating()
# 図形ウィンドウを強制的に再描画して、バウンディングボックス計算を行う.
scene.update_figure_window()
# 選択された形状のX方向のサイズが「D」の長さになるようにスケーリング.
shape = scene.active_shape() # 選択されている形状.
type = shape.type # 選択されている形状の種類。4の場合は線形状.
bbSize = shape.bounding_box_size # shapeの形状のバウンディングボックスサイズ.
scale = D / bbSize[0]
bbSize = [bbSize[0] * scale, bbSize[1] * scale, bbSize[2] * scale]
shape.bounding_box_size = bbSize
scene.update_figure_window() # 図形ウィンドウを強制的に再描画.
# 選択された形状のX方向が、X=0となるように位置調整.
centerPos = shape.center_position # shapeの中心位置.
centerPos = [0.0, centerPos[1], centerPos[2]]
shape.center_position = centerPos
scene.update_figure_window() # 図形ウィンドウを強制的に再描画.
# X軸中心に90度回転させて、歯を上向きにする (※ 新たに追加しました).
rotM = get_rotateX(90.0)
shape.transform(rotM)
# 半径方向の移動距離(半径Rよりも少し短くなる).
R2 = math.cos((angle / 2.0) * math.pi / 180.0) * R
# 選択された形状のZ方向に-R2分移動.
centerPos = shape.center_position
centerPos = [centerPos[0], centerPos[1], (-bbSize[2] * 0.5) - R2]
shape.center_position = centerPos
scene.update_figure_window() # 図形ウィンドウを強制的に再描画.
# 「開いた線形状」を円周上に複製する.
for i in range(gCount - 1):
scene.copy_object([0, 0, 0], None, [0, 360 - angle, 0], None)
if type == 4: # 線形状の場合.
# 「開いた線形状」を連結.
for i in range(gCount - 1):
scene.memory()
scene.select_sister(1)
scene.append()
# 不要な「開いた線形状」を削除していく.
for i in range(gCount - 1):
scene.select_brother(1)
scene.clear()
# 「開いた線形状」を「閉じた線形状」にする.
scene.active_shape().closed = 1
# 形状の作成終了.
scene.end_creating()
「def get_rotateX(angle)」は、X軸中心に指定の角度回転させたときの行列を計算する「関数」です。
スクリプトでの関数は、処理を行い結果を返す一連の機能を指します。
呼び出し側では、
rotM = get_rotateX(90.0)
としており、これはX軸中心に90度回転させたときの行列を「rotM」に返しています。
行列とは ?
3DCGの場合は、形状の「移動」「回転」「スケール」などを掛け合わせることで、
形状の位置や回転、サイズを調整できます。
Shade3Dの場合は、パートをブラウザで選択したときの形状情報ウィンドウの「パート属性」の「マトリクス」が行列の実際の値になります。
4×4個の実数値で表現されます。
これは、展開すると「変換要素」のタブを選択したときの「スケール」「せん断」「回転」「移動」に分解されます。
パート以外でも、シーンに存在する形状はすべてに対して行列を内部的に持っています。
例えば、
X軸中心に90度回転させてから移動する、という処理を行う場合、
「X軸中心に90度回転させる行列」「移動する行列」を掛け合わせて複数の処理を順番に行います。
また、ブラウザで見て階層構造になっている場合に、
それぞれのパートを親までたどって個々のパートの行列をかけ合わせていくことで最終的なシーン上の位置や回転を計算できます。
これを「アフィン変換」と呼びます。
ここでは考え方だけ書いて、計算式は飛ばします。
それで、以下のスクリプトで何をしているかというと、
# X軸中心に90度回転させて、歯を上向きにする.
rotM = get_rotateX(90.0)
shape.transform(rotM)
上面図から見えるXZ平面上にある線形状を、
X軸を中心に90度回転させる、という計算になります。
「shape.transform(rotM)」が行列を乗算するShade3Dが用意したスクリプト関数です。
これを半径の距離分移動させて円周上にぐるっと複製して配置することで、上向きの歯車の線形状ができます。
それを上記のスクリプトで行っています。
このX軸中心に90度回転させる処理以外は「歯車のベース部分をスクリプトで効率化してモデリング」での説明と同じになります。
スクリプトを実行
では、このスクリプトを実際に実行してみます。
6つのポイントで構成される1つの歯をあらわす「開いた線形状」をブラウザで選択し、
このスクリプトを実行しました。
以下のように歯が上向きの「閉じた線形状」が生成されました。
閉じた線形状に厚みを付ける
「自由曲面」パートを生成し、ブラウザで1つ前でスクリプトにて作成した「閉じた線形状」を自由曲面パート内に入れます。
「閉じた線形状」を複製し、自由曲面内の上の「閉じた線形状」を選択します。
ツールボックスの「作成」-「移動/複製」-「移動」-「数値入力」を選択。
図形ウィンドウの上面図の原点をクリックすると「トランスフォーメーション」ダイアログボックスが表示されます。
ここで「拡大縮小」のXとZを0.9としてOKボタンを押します。
選択した形状が原点を中心にXZ方向に0.9倍されて、以下のようになります。
冠歯車の歯の部分ができました。
次に、側面を埋めていきます。
冠歯車の側面を閉じる
自由曲面パート内の「閉じた線形状」の一番上と一番下を複製します。
一番上の「閉じた線形状」を選択し、正面図でY軸方向の拡大縮小のマニピュレータを押し下げて、
Y軸方向に一直線になるようにします。
このとき、ツールパラメータの「移動:拡大縮小」でYの値を0.0にするとポイントのY値は同じ値になります。
一直線になって円状の「閉じた線形状」になります。
この後、正面図でマニピュレータを使って-Y方向に移動させます。
これで、冠歯車の内側の面が閉じられました。
同様に、自由曲面パートの一番下の「閉じた線形状」を選択して同じ処理を行います。
以下のようになりました。
冠歯車の上面と底面を閉じる
自由曲面パート内の一番上の「閉じた線形状」を複製し、「一点に収束」を実行します。
これで、上面が閉じられました。
自由曲面パートの一番下の「閉じた線形状」を複製し、正面図または右面図でマニピュレータを使って-Y方向に少し移動させます。
これは、上面と底面が同じY位置になって厚みがゼロにならないようにしています。
再度「閉じた線形状」を複製し、「一点に収束」を実行します。
7つの「閉じた線形状」で冠歯車ができました。
円柱を配置し、冠歯車の軸とする
ツールボックスの「作成」-「形状」-「一般」-「円柱」を選択し、
冠歯車の中心に円柱を配置しました。
最後に「冠歯車」パートを作成し、ブラウザで冠歯車を構成する自由曲面と円柱をパート内に入れます。
これで、冠歯車が完成しました。
平歯車を移動/回転させて、かみ合う位置に持ってきました。
これで、冠歯車のモデリングができました。
同じ歯車でも、種類によってモデリング工程が異なるということが分かってきました。
でも、基本は変わらずに応用になっています。
そして、だんだんとスクリプトで行う作業が増えてきましたね。
次回は、この冠歯車と平歯車をアニメーションさせます。