課題
仕様
プログラムは次の仕様を満たすようにしてください. その他の機能を追加することも自由です.
- 中心に恒星を一つ配置する
- 恒星系には少なくとも惑星を二つ以上配置する
- 少なくとも一つの惑星に衛星を一つ以上配置する
- 惑星,衛星の公転軌道を描画する
- 惑星,衛星の公転運動のアニメーション機能を持たせる
また次のように単純化したモデルを考えることにします. 余裕があれば,より複雑なモデルを考えてもよいでしょう.
- 恒星,惑星,衛星はそれぞれ単一の材質からなる球で描くものとする
- 惑星,衛星の軌道面はすべて同一であるとする
- 惑星,衛星の軌道は恒星あるいは惑星を中心とする同心円とする
- 惑星,衛星の公転速度は適宜定め,物理法則に従う必要はない
なお今回作成する恒星系はあくまでも動きを見るもので,プログラムでは光源は恒星とは独立して定めてよいことにします.
課題の進め方
課題を行うにあたって,次のテンプレートファイルをダウンロードして利用してください.
このテンプレートでは視点はz軸上(z > 0)にあって,原点をとらえるようになっています.
またサンプルプログラムも参考にしてください.
恒星系を組み立てるには,モデル・ビュー変換行列のスタックをうまく利用して,階層的なモデリングを行います. GL.Translate,GL.RotateとGL.PushMatrix,GL.PopMatrixをうまく組み合わせてください. なお,後に記述した変換から先に適用されることに注意してください.
恒星系の構築の指針
衛星をもつ惑星系を含む恒星系を構築する際には, 恒星系の中に惑星系を配置することになります. 惑星系は恒星を中心に周回します. また惑星系内では,衛星が惑星を中心として公転することになります.
そこで恒星系を構築するには,まず恒星を基準にして,惑星系の配置を考えます. 次に惑星系においては,惑星を基準として,衛星の配置を考えます.
恒星系の各惑星系(衛星が存在しない惑星もありえます)には,それぞれ恒星を基準とした変換をかけます.惑星系同士は独立していて,それらの配置の間には関係はありません. そこで一つの惑星系を配置したら,その描画に用いた変換を外してから次の惑星系を配置します. このためにPushMatrix,PopMatrixを使います.
星の描き方
テンプレートファイルには星を描くメソッドstarが定義されています. starメソッドでは,マテリアルを指定して,球面として星を描きます.
## 恒星のデータ SUN_RADIUS=0.7 # 半径 SUN_SLICES= 20 # 経線の本数 SUN_STACKS= SUN_SLICES # 緯線の本数 # マテリアル SUN_MATERIAL={ :ambient=>[0.8,0.2,0.1], # :ambient =>[Ra,Ga,Ba] 環境光反射率 :diffuse=>[1.0,0.2,0.1], # :diffuse =>[Rd,Gd,Bd] 拡散光反射率 :specular=>[0.7,0.2,0.1], # :specular=>[Rs,Gs,Bs] 鏡面光反射率 :shininess=>0.5 # 鏡面度/128→[0,1] } def star(size,slices,stacks,material) # 材質の設定 GLMaterial.set(material) # 球面の描画 GLUT.SolidSphere(size,slices,stacks) end display = Proc.new { # 恒星を描画 star(SUN_RADIUS,SUN_SLICES,SUN_STACKS,SUN_MATERIAL) }
球面の描画方法
球面は多角形の集まりで近似的に表現されます. (原点中心の)球面を描くには次のようにします.
GLUT.SolidSphere(radius,slices,stacks)
radiusは球の半径です.slices,stacksは近似の度合いを示します. これら二つの値を大きくすれば,より細かく近似することになります. 一方小さくした場合には粗い近似になります. 具体的にはslicesとstacksで与えられた数(整数)に基づいて,経線と緯線を等間隔に引いて,それらの線で区切られた一つ一つの区画を面として描くことになります. あまり細かくしすぎると描画にかかる時間が不必要に長くなりますので注意してください.
マテリアルの指定方法
今回のテンプレートでは,マテリアルは次のように定義して利用できるようになっています. 上の例も参照してください.
# マテリアルの定義 マテリアル名={ :ambient=>[Ra,Ga,Ba], # 環境光反射率(赤,緑,青) :diffuse=>[Rd,Gd,Bd], # 拡散光反射率(赤,緑,青) :specular=>[Rs,Gs,Bs] # 鏡面光反射率(赤,緑,青) :shininess=>S # S==鏡面度/128 ∈ [0,1] } # マテリアルの設定 GLMaterial.set(マテリアル名)
公転軌道の描き方
公転軌道はシェーディングをOFFにして描きます. テンプレートには原点を中心として平面z=0上に白い円を描くメソッドorbitが定義されています. 円を描くのにMGLUtils.circleメソッドを使っています.
def orbit(size) GL.Disable(GL::LIGHTING) # Lighting/Shading OFF GL.Color(COLOR_ORBIT) # 色の設定 MGLUtils.circle([0,0],size) # 円を描く GL.Enable(GL::LIGHTING) # Lighting/Shading ON end #### 描画コールバック ######## display = Proc.new { # 公転軌道を描くテスト orbit(SUN_RADIUS*5) }
なおMGLUtils.circleメソッドは標準のOpenGLでは定義されていません. MGLUtils.circleメソッドを使わないで円を描くには,GL::LINE_LOOPを使います.
GL.Disable(GL::LIGHTING)
GL.Begin(GL::LINE_LOOP)
# 繰り返しを使って,公転軌道上の頂点を順に発生させる
GL.End()
GL.Enable(GL::LIGHTING)
球面の場合と同様に必要以上に多くの頂点をとると描画にかかる時間が不必要に長くなりますので注意してください.