課題
仕様
プログラムは次の仕様を満たすようにして下さい. その他の機能を追加することも自由です.
- 中心に恒星を一つ配置する
- 恒星系には少なくとも惑星を二つ以上配置する
- 少なくとも一つの惑星に衛星を一つ以上配置する
- 惑星,衛星の公転軌道を描画する
- 惑星,衛星の公転運動のアニメーション機能を持たせる
また次のように単純化したモデルを考えることにします. 余裕があれば,より複雑なモデルを考えてもよいでしょう.
- 恒星,惑星,衛星はそれぞれ単一の材質からなる球で描くものとする
- 惑星,衛星の軌道面はすべて同一であるとする
- 惑星,衛星の軌道は恒星あるいは惑星を中心とする同心円とする
- 惑星,衛星の公転速度は適宜定め,物理法則に従う必要はない
なお今回作成する恒星系はあくまでも動きを見るもので,プログラムでは光源は恒星とは独立して定めてよいことにします.
課題の進め方
課題を行うにあたって,次のテンプレートファイルをダウンロードして利用して下さい.
このテンプレートでは視点は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=[[0.8,0.2,0.1],[1.0,0.2,0.1],[0.7,0.2,0.1],64.0] def star(size,slices,stacks,material) # 材質の設定 MATERIAL_ITEMS.each_with_index do |item,i| GL.Material(GL::FRONT,item,material[i]) if material[i] end # 球面の描画 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で与えられた数(整数)に基づいて,経線と緯線を等間隔に引いて,それらの線で区切られた一つ一つの区画を面として描くことになります. あまり細かくしすぎると描画にかかる時間が不必要に長くなりますので注意して下さい.
公転軌道の描き方
公転軌道はシェーディングをOFFにして描きます. テンプレートには原点を中心として平面z=0上に白い円を描くメソッドorbitが定義されています. 円を描くのにMGLUtils.circleメソッドを使っています.
def orbit(size) GL.Disable(GL::LIGHTING) # シェーディングOFF GL.Color(*COLOR_WHITE) # 色の設定 MGLUtils.circle([0,0],size) # 円を描く GL.Enable(GL::LIGHTING) # シェーディング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)
球面の場合と同様に必要以上に多くの頂点をとると描画にかかる時間が不必要に長くなりますので注意して下さい.